home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / jigsaw.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-13  |  80.7 KB  |  2,882 lines

  1. /*
  2.  * jigsaw - a plug-in for the GIMP
  3.  *
  4.  * Copyright (C) Nigel Wetten
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  *
  20.  * Contact info: nigel@cs.nwu.edu
  21.  *
  22.  * Version: 1.0.0
  23.  *
  24.  * Version: 1.0.1
  25.  *
  26.  * tim coppefield [timecop@japan.co.jp]
  27.  *
  28.  * Added dynamic preview mode.
  29.  *
  30.  * Damn, this plugin is the tightest piece of code I ever seen.
  31.  * I wish all filters in the plugins operated on guchar *buffer
  32.  * of the entire image :) sweet stuff.
  33.  *
  34.  */
  35.  
  36. #include "config.h"
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41.  
  42. #include <gtk/gtk.h>
  43.  
  44. #include <libgimp/gimp.h>
  45. #include <libgimp/gimpui.h>
  46.  
  47. #include "libgimp/stdplugins-intl.h"
  48.  
  49.  
  50. #define PREVIEW_SIZE    128 
  51.  
  52.  
  53. typedef enum 
  54. {
  55.   BEZIER_1, 
  56.   BEZIER_2
  57. } style_t;
  58.  
  59. typedef enum 
  60. {
  61.   LEFT, 
  62.   RIGHT, 
  63.   UP, 
  64.   DOWN
  65. } bump_t;
  66.  
  67.  
  68. static void query (void);
  69. static void run   (gchar   *name,
  70.            gint     nparams,
  71.            GimpParam  *param,
  72.            gint    *nreturn_vals,
  73.            GimpParam **return_vals);
  74.  
  75. static gint jigsaw     (gboolean preview_mode);
  76.  
  77. static void  jigsaw_radio_button_update (GtkWidget *widget, gpointer data);
  78. static void  dialog_box (void);
  79. static void  fill_preview_with_thumb (GtkWidget *preview_widget, 
  80.                       gint32     drawable_ID);
  81. static GtkWidget *preview_widget  (GimpDrawable *drawable);
  82.  
  83. static void run_callback          (GtkWidget *widget, gpointer   data);
  84. static void check_button_callback (GtkWidget *widget, gpointer   data);
  85.  
  86. static void draw_jigsaw           (guchar    *buffer,
  87.                                    gint       bufsize,
  88.                    gint       width, 
  89.                    gint       height, 
  90.                    gint       bytes, 
  91.                    gboolean   preview_mode);
  92.  
  93. static void draw_vertical_border   (guchar *buffer, gint bufsize,
  94.                                     gint width, gint height,
  95.                     gint bytes, gint x_offset, gint ytiles,
  96.                     gint blend_lines, gdouble blend_amount,
  97.                     gboolean   preview_mode);
  98. static void draw_horizontal_border (guchar *buffer, gint bufsize,
  99.                                     gint width, gint bytes,
  100.                                     gint y_offset, gint xtiles,
  101.                     gint blend_lines, gdouble blend_amount,
  102.                     gboolean   preview_mode);
  103. static void draw_vertical_line     (guchar *buffer, gint bufsize,
  104.                                     gint width, gint bytes,
  105.                     gint px[2], gint py[2],
  106.                     gboolean   preview_mode);
  107. static void draw_horizontal_line   (guchar *buffer, gint bufsize,
  108.                                     gint width, gint bytes,
  109.                     gint px[2], gint py[2], 
  110.                     gboolean   preview_mode);
  111. static void darken_vertical_line   (guchar *buffer, gint bufsize,
  112.                                     gint width, gint bytes,
  113.                     gint *px, gint *py, gdouble delta,
  114.                     gboolean   preview_mode);
  115. static void lighten_vertical_line  (guchar *buffer, gint bufsize,
  116.                                     gint width, gint bytes,
  117.                     gint *px, gint *py, gdouble delta,
  118.                     gboolean   preview_mode);
  119. static void darken_horizontal_line (guchar *buffer, gint bufsize,
  120.                                     gint width, gint bytes,
  121.                     gint *px, gint *py, gdouble delta,
  122.                     gboolean   preview_mode);
  123. static void lighten_horizontal_line(guchar *buffer, gint bufsize,
  124.                                     gint width, gint bytes,
  125.                     gint *px, gint *py, gdouble delta,
  126.                     gboolean   preview_mode);
  127. static void draw_right_bump        (guchar *buffer, gint bufsize,
  128.                                     gint width, gint bytes,
  129.                     gint x_offset, gint curve_start_offset,
  130.                     gint steps, gboolean   preview_mode);
  131. static void draw_left_bump         (guchar *buffer, gint bufsize,
  132.                                     gint width, gint bytes,
  133.                     gint x_offset, gint curve_start_offset,
  134.                     gint steps, gboolean   preview_mode);
  135. static void draw_up_bump           (guchar *buffer, gint bufsize,
  136.                                     gint width, gint bytes,
  137.                     gint y_offset, gint curve_start_offset,
  138.                     gint steps, gboolean   preview_mode);
  139. static void draw_down_bump         (guchar *buffer, gint bufsize,
  140.                                     gint width, gint bytes,
  141.                     gint y_offset, gint curve_start_offset,
  142.                     gint steps, gboolean   preview_mode);
  143. static void darken_right_bump      (guchar *buffer, gint bufsize,
  144.                                     gint width, gint bytes,
  145.                     gint x_offset, gint curve_start_offset,
  146.                     gint steps, gdouble delta, gint counter,
  147.                     gboolean   preview_mode);
  148. static void lighten_right_bump     (guchar *buffer, gint bufsize,
  149.                                     gint width, gint bytes,
  150.                     gint x_offset, gint curve_start_offset,
  151.                     gint steps, gdouble delta, gint counter,
  152.                     gboolean   preview_mode);
  153. static void darken_left_bump       (guchar *buffer, gint bufsize,
  154.                                     gint width, gint bytes,
  155.                     gint x_offset, gint curve_start_offset,
  156.                     gint steps, gdouble delta, gint counter,
  157.                     gboolean   preview_mode);
  158. static void lighten_left_bump      (guchar *buffer, gint bufsize,
  159.                                     gint width, gint bytes,
  160.                     gint x_offset, gint curve_start_offset,
  161.                     gint steps, gdouble delta, gint counter,
  162.                     gboolean   preview_mode);
  163. static void darken_up_bump         (guchar *buffer, gint bufsize,
  164.                                     gint width, gint bytes,
  165.                     gint y_offset, gint curve_start_offest,
  166.                     gint steps, gdouble delta, gint counter,
  167.                     gboolean   preview_mode);
  168. static void lighten_up_bump        (guchar *buffer, gint bufsize,
  169.                                     gint width, gint bytes,
  170.                     gint y_offset, gint curve_start_offset,
  171.                     gint steps, gdouble delta, gint counter,
  172.                     gboolean   preview_mode);
  173. static void darken_down_bump       (guchar *buffer, gint bufsize,
  174.                                     gint width, gint bytes,
  175.                     gint y_offset, gint curve_start_offset,
  176.                     gint steps, gdouble delta, gint counter,
  177.                     gboolean   preview_mode);
  178. static void lighten_down_bump      (guchar *buffer, gint bufsize,
  179.                                     gint width, gint bytes,
  180.                     gint y_offset, gint curve_start_offset,
  181.                     gint steps, gdouble delta, gint counter,
  182.                     gboolean   preview_mode);
  183. static void generate_grid          (gint width, gint height, gint xtiles, gint ytiles,
  184.                     gint *x, gint *y);
  185. static void generate_bezier        (gint px[4], gint py[4], gint steps,
  186.                     gint *cachex, gint *cachey);
  187. static void malloc_cache           (void);
  188. static void free_cache             (void);
  189. static void init_right_bump        (gint width, gint height);
  190. static void init_left_bump         (gint width, gint height);
  191. static void init_up_bump           (gint width, gint height);
  192. static void init_down_bump         (gint width, gint height);
  193. static void draw_bezier_line       (guchar *buffer, gint bufsize,
  194.                                     gint width, gint bytes,
  195.                     gint steps, gint *cx, gint *cy, 
  196.                     gboolean preview_mode);
  197. static void darken_bezier_line     (guchar *buffer, gint bufsize,
  198.                                     gint width, gint bytes,
  199.                     gint x_offset, gint y_offset, gint steps,
  200.                     gint *cx, gint *cy, gdouble delta, 
  201.                     gboolean preview_mode);
  202. static void lighten_bezier_line    (guchar *buffer, gint bufsize,
  203.                                     gint width, gint bytes,
  204.                     gint x_offset, gint y_offset, gint steps,
  205.                     gint *cx, gint *cy, gdouble delta, 
  206.                     gboolean preview_mode);
  207. static void draw_bezier_vertical_border   (guchar *buffer, gint bufsize,
  208.                                            gint width, gint height,
  209.                                            gint bytes,
  210.                        gint x_offset, gint xtiles,
  211.                        gint ytiles, gint blend_lines,
  212.                        gdouble blend_amount, gint steps, 
  213.                        gboolean preview_mode);
  214. static void draw_bezier_horizontal_border (guchar *buffer, gint bufsize,
  215.                                            gint width, gint height,
  216.                                            gint bytes,
  217.                        gint x_offset, gint xtiles,
  218.                        gint ytiles, gint blend_lines,
  219.                        gdouble blend_amount, gint steps, 
  220.                        gboolean preview_mode);
  221. static void check_config           (gint width, gint height);
  222.  
  223.                 
  224.  
  225. #define PLUG_IN_NAME    "jigsaw"
  226. #define PLUG_IN_STORAGE "jigsaw-storage"
  227.  
  228. #define XFACTOR2 0.0833
  229. #define XFACTOR3 0.2083
  230. #define XFACTOR4 0.2500
  231.  
  232. #define XFACTOR5 0.2500
  233. #define XFACTOR6 0.2083
  234. #define XFACTOR7 0.0833
  235.  
  236. #define YFACTOR2 0.1000
  237. #define YFACTOR3 0.2200
  238. #define YFACTOR4 0.1000
  239.  
  240. #define YFACTOR5 0.1000
  241. #define YFACTOR6 0.4666
  242. #define YFACTOR7 0.1000
  243. #define YFACTOR8 0.2000
  244.  
  245. #define MAX_VALUE 255
  246. #define MIN_VALUE 0
  247. #define DELTA 0.15
  248.  
  249. #define BLACK_R 30
  250. #define BLACK_G 30
  251. #define BLACK_B 30
  252.  
  253. #define WALL_XFACTOR2 0.05
  254. #define WALL_XFACTOR3 0.05
  255. #define WALL_YFACTOR2 0.05
  256. #define WALL_YFACTOR3 0.05
  257.  
  258. #define WALL_XCONS2 0.2
  259. #define WALL_XCONS3 0.3
  260. #define WALL_YCONS2 0.2
  261. #define WALL_YCONS3 0.3
  262.  
  263. #define FUDGE 1.2
  264.  
  265. #define MIN_XTILES 1
  266. #define MAX_XTILES 20
  267. #define MIN_YTILES 1
  268. #define MAX_YTILES 20
  269. #define MIN_BLEND_LINES 0
  270. #define MAX_BLEND_LINES 10
  271. #define MIN_BLEND_AMOUNT 0
  272. #define MAX_BLEND_AMOUNT 1.0
  273.  
  274. #define SCALE_WIDTH 200
  275. #define ENTRY_WIDTH 40
  276.  
  277. #define DRAW_POINT(buffer, bufsize, index)         \
  278.   do                                               \
  279.     {                                              \
  280.       if ((index) >= 0 && (index) + 2 < (bufsize)) \
  281.         {                                          \
  282.           buffer[(index) + 0] = BLACK_R;           \
  283.           buffer[(index) + 1] = BLACK_G;           \
  284.           buffer[(index) + 2] = BLACK_B;           \
  285.         }                                          \
  286.     }                                              \
  287.   while (0)
  288.  
  289. #define DARKEN_POINT(buffer, bufsize, index, delta, temp)                \
  290.   do                                                                     \
  291.     {                                                                    \
  292.       if ((index) >= 0 && (index) + 2 < (bufsize))                       \
  293.         {                                                                \
  294.           temp = MAX (buffer[(index) + 0] * (1.0 - (delta)), MIN_VALUE); \
  295.           buffer[(index) + 0] = temp;                                    \
  296.           temp = MAX (buffer[(index) + 1] * (1.0 - (delta)), MIN_VALUE); \
  297.           buffer[(index) + 1] = temp;                                    \
  298.           temp = MAX (buffer[(index) + 2] * (1.0 - (delta)), MIN_VALUE); \
  299.           buffer[(index) + 2] = temp;                                    \
  300.         }                                                                \
  301.     }                                                                    \
  302.   while (0)
  303.  
  304. #define LIGHTEN_POINT(buffer, bufsize, index, delta, temp)               \
  305.   do                                                                     \
  306.     {                                                                    \
  307.       if ((index) >= 0 && (index) + 2 < (bufsize))                       \
  308.         {                                                                \
  309.           temp = MIN (buffer[(index) + 0] * (1.0 + (delta)), MAX_VALUE); \
  310.           buffer[(index) + 0] = temp;                                    \
  311.           temp = MIN (buffer[(index) + 1] * (1.0 + (delta)), MAX_VALUE); \
  312.           buffer[(index) + 1] = temp;                                    \
  313.           temp = MIN (buffer[(index) + 2] * (1.0 + (delta)), MAX_VALUE); \
  314.           buffer[(index) + 2] = temp;                                    \
  315.         }                                                                \
  316.     }                                                                    \
  317.   while (0)
  318.  
  319.  
  320. GimpPlugInInfo PLUG_IN_INFO =
  321. {
  322.   NULL,
  323.   NULL,
  324.   query,
  325.   run
  326. };
  327.  
  328. struct config_tag
  329. {
  330.   gint    x;
  331.   gint    y;
  332.   style_t style;
  333.   gint    blend_lines;
  334.   gdouble blend_amount;
  335. };
  336.  
  337.  
  338. typedef struct config_tag config_t;
  339.  
  340. static config_t config =
  341. {
  342.   5,
  343.   5,
  344.   BEZIER_1,
  345.   3,
  346.   0.5
  347. };
  348.  
  349. struct globals_tag
  350. {
  351.   GimpDrawable *drawable;
  352.   gint  *cachex1[4];
  353.   gint  *cachex2[4];
  354.   gint  *cachey1[4];
  355.   gint  *cachey2[4];
  356.   gint  steps[4];
  357.   gint  *gridx;
  358.   gint  *gridy;
  359.   gint **blend_outer_cachex1[4];
  360.   gint **blend_outer_cachex2[4];
  361.   gint **blend_outer_cachey1[4];
  362.   gint **blend_outer_cachey2[4];
  363.   gint **blend_inner_cachex1[4];
  364.   gint **blend_inner_cachex2[4];
  365.   gint **blend_inner_cachey1[4];
  366.   gint **blend_inner_cachey2[4];
  367.   gint   dialog_result;
  368.   gint   tooltips;
  369. };
  370.  
  371. typedef struct globals_tag globals_t;
  372.  
  373. static globals_t globals =
  374. {
  375.   0,
  376.   {0, 0, 0, 0},
  377.   {0, 0, 0, 0},
  378.   {0, 0, 0, 0},
  379.   {0, 0, 0, 0},
  380.   {0, 0, 0, 0},
  381.   0,
  382.   0,
  383.   {0, 0, 0, 0},
  384.   {0, 0, 0, 0},
  385.   {0, 0, 0, 0},
  386.   {0, 0, 0, 0},
  387.   {0, 0, 0, 0},
  388.   {0, 0, 0, 0},
  389.   {0, 0, 0, 0},
  390.   {0, 0, 0, 0},
  391.   -1,
  392.   1
  393. };
  394.  
  395. /* preview globals */
  396. static guchar *preview_bits;
  397. static GtkWidget *preview;
  398.  
  399. MAIN ()
  400.  
  401. static void
  402. query (void)
  403. {
  404.   static GimpParamDef args[] =
  405.   {
  406.     { GIMP_PDB_INT32, "run_mode", "Interactive, Non-interactive, Last-Vals" },
  407.     { GIMP_PDB_IMAGE, "image", "Input image" },
  408.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  409.     { GIMP_PDB_INT32, "x", "Number of tiles across > 0" },
  410.     { GIMP_PDB_INT32, "y", "Number of tiles down > 0" },
  411.     { GIMP_PDB_INT32, "style", "The style/shape of the jigsaw puzzle, 0 or 1" },
  412.     { GIMP_PDB_INT32, "blend_lines", "Number of lines for shading bevels >= 0" },
  413.     { GIMP_PDB_FLOAT, "blend_amount", "The power of the light highlights 0 =< 5" }
  414.   };
  415.   static gint nargs = sizeof (args) / sizeof (args[0]);
  416.  
  417.   gimp_install_procedure ("plug_in_jigsaw",
  418.               "Renders a jigsaw puzzle look",
  419.               "Jigsaw puzzle look",
  420.               "Nigel Wetten",
  421.               "Nigel Wetten",
  422.               "May 2000",
  423.               N_("<Image>/Filters/Render/Pattern/Jigsaw..."),
  424.               "RGB*",
  425.               GIMP_PLUGIN,
  426.               nargs, 0,
  427.               args, NULL);
  428. }
  429.  
  430. static void
  431. run (gchar   *name,
  432.      gint     nparams,
  433.      GimpParam  *param,
  434.      gint    *nreturn_vals,
  435.      GimpParam **return_vals)
  436. {
  437.   static GimpParam values[1];
  438.   GimpDrawable *drawable;
  439.   GimpRunModeType run_mode;
  440.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  441.  
  442.   run_mode = param[0].data.d_int32;
  443.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  444.   globals.drawable = drawable;
  445.   gimp_tile_cache_ntiles(drawable->width / gimp_tile_width() + 1);
  446.  
  447.   switch (run_mode)
  448.     {
  449.     case GIMP_RUN_NONINTERACTIVE:
  450.       INIT_I18N();
  451.       if (nparams == 8)
  452.     {
  453.       config.x = param[3].data.d_int32;
  454.       config.y = param[4].data.d_int32;
  455.       config.style = param[5].data.d_int32;
  456.       config.blend_lines = param[6].data.d_int32;
  457.       config.blend_amount = param[7].data.d_float;
  458.       if (jigsaw(0) == -1)
  459.         {
  460.           status = GIMP_PDB_EXECUTION_ERROR;
  461.         }
  462.     }
  463.       else
  464.     {
  465.       status = GIMP_PDB_CALLING_ERROR;
  466.     }
  467.       break;
  468.       
  469.     case GIMP_RUN_INTERACTIVE:
  470.       INIT_I18N_UI();
  471.       gimp_get_data("plug_in_jigsaw", &config);
  472.       gimp_get_data(PLUG_IN_STORAGE, &globals.tooltips);
  473.       dialog_box();
  474.       if (globals.dialog_result == -1)
  475.     {
  476.       status = GIMP_PDB_EXECUTION_ERROR;
  477.       break;
  478.     }
  479.       gimp_progress_init( _("Assembling Jigsaw"));
  480.       if (jigsaw(0) == -1)
  481.     {
  482.       status = GIMP_PDB_CALLING_ERROR;
  483.       break;
  484.     }
  485.       gimp_set_data("plug_in_jigsaw", &config, sizeof(config_t));
  486.       gimp_set_data(PLUG_IN_STORAGE, &globals.tooltips,
  487.             sizeof(globals.tooltips));
  488.       gimp_displays_flush();
  489.       g_free(preview_bits);
  490.       break;
  491.       
  492.     case GIMP_RUN_WITH_LAST_VALS:
  493.       INIT_I18N();
  494.       gimp_get_data("plug_in_jigsaw", &config);
  495.       if (jigsaw(0) == -1)
  496.     {
  497.       status = GIMP_PDB_EXECUTION_ERROR;
  498.       gimp_message("An execution error occured.");
  499.     }
  500.       else
  501.     {
  502.       gimp_displays_flush();
  503.     }
  504.  
  505.     }  /* switch */
  506.       
  507.   gimp_drawable_detach(drawable);
  508.   
  509.   *nreturn_vals = 1;
  510.   *return_vals = values;
  511.   values[0].type = GIMP_PDB_STATUS;
  512.   values[0].data.d_status = status;
  513.  
  514.   return;
  515. }
  516.  
  517. static gint
  518. jigsaw (gboolean preview_mode)
  519. {
  520.   GimpPixelRgn src_pr, dest_pr;
  521.   guchar *buffer;
  522.   GimpDrawable *drawable = globals.drawable;
  523.   gint width;
  524.   gint height;
  525.   gint bytes;
  526.   gint buffer_size;
  527.  
  528.   srand((gint)NULL);
  529.  
  530.   if (preview_mode) 
  531.     {
  532.       width  = GTK_PREVIEW (preview)->buffer_width;
  533.       height = GTK_PREVIEW (preview)->buffer_height;
  534.       bytes  = GTK_PREVIEW (preview)->bpp;
  535.       buffer_size = GTK_PREVIEW (preview)->rowstride * height;
  536.     } 
  537.   else 
  538.     {
  539.       width  = drawable->width;
  540.       height = drawable->height;
  541.       bytes  = drawable->bpp;
  542.       buffer_size = bytes * width * height;
  543.     }
  544.  
  545.   /* setup image buffer */
  546.   buffer = g_malloc (buffer_size);
  547.  
  548.   if (preview_mode) 
  549.     {
  550.       memcpy (buffer, preview_bits, buffer_size);
  551.     } 
  552.   else 
  553.     {
  554.       gimp_pixel_rgn_init (&src_pr,  drawable, 0, 0, width, height, FALSE, FALSE);
  555.       gimp_pixel_rgn_init (&dest_pr, drawable, 0, 0, width, height, TRUE, TRUE);
  556.       gimp_pixel_rgn_get_rect (&src_pr, buffer, 0, 0, width, height);
  557.     }
  558.  
  559.   check_config (width, height);
  560.   globals.steps[LEFT] = globals.steps[RIGHT] = globals.steps[UP]
  561.     = globals.steps[DOWN] = (config.x < config.y) ?
  562.     (width / config.x * 2) : (height / config.y * 2);
  563.  
  564.   malloc_cache ();
  565.   draw_jigsaw (buffer, buffer_size, width, height, bytes, preview_mode);
  566.   free_cache ();
  567.  
  568.   /* cleanup */
  569.   if (preview_mode) 
  570.     {
  571.       memcpy (GTK_PREVIEW (preview)->buffer, buffer, buffer_size);
  572.       gtk_widget_queue_draw (preview);
  573.     } 
  574.   else 
  575.     {
  576.       gimp_pixel_rgn_set_rect (&dest_pr, buffer, 0, 0, width, height);
  577.       gimp_drawable_flush (drawable);
  578.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  579.       gimp_drawable_update (drawable->id, 0, 0, width, height);
  580.     }
  581.  
  582.   g_free(buffer);
  583.  
  584.   return 0;
  585. }
  586.  
  587. static void
  588. generate_bezier (gint  px[4],
  589.          gint  py[4],
  590.          gint  steps,
  591.          gint *cachex,
  592.          gint *cachey)
  593. {
  594.   gdouble t = 0.0;
  595.   gdouble sigma = 1.0 / steps;
  596.   gint i;
  597.  
  598.   for (i = 0; i < steps; i++)
  599.     {
  600.       gdouble t2, t3, x, y, t_1;
  601.  
  602.       t += sigma;
  603.       t2 = t * t;
  604.       t3 = t2 * t;
  605.       t_1 = 1 - t;
  606.       x = t_1 * t_1 * t_1 * px[0]
  607.     + 3 * t * t_1 * t_1 * px[1]
  608.     + 3 * t2 * t_1 * px[2]
  609.     + t3 * px[3];
  610.       y = t_1 * t_1 * t_1 * py[0]
  611.     + 3 * t * t_1 * t_1 * py[1]
  612.     + 3 * t2 * t_1 * py[2]
  613.     + t3 * py[3];
  614.       cachex[i] = (gint) (x + 0.2);
  615.       cachey[i] = (gint) (y + 0.2);
  616.     }  /* for */
  617.   return;
  618. }
  619.  
  620. static void
  621. draw_jigsaw (guchar   *buffer,
  622.              gint      bufsize,
  623.          gint      width,
  624.          gint      height,
  625.          gint      bytes,
  626.          gboolean  preview_mode)
  627. {
  628.   gint i;
  629.   gint *x, *y;
  630.   gint xtiles = config.x;
  631.   gint ytiles = config.y;
  632.   gint xlines = xtiles - 1;
  633.   gint ylines = ytiles - 1;
  634.   gint blend_lines = config.blend_lines;
  635.   gdouble blend_amount = config.blend_amount;
  636.   gint steps = globals.steps[RIGHT];
  637.   style_t style = config.style;
  638.   gint progress_total = xlines + ylines - 1;
  639.  
  640.   globals.gridx = g_new (gint, xtiles);
  641.   globals.gridy = g_new (gint, ytiles);
  642.   x = globals.gridx;
  643.   y = globals.gridy;
  644.  
  645.   generate_grid (width, height, xtiles, ytiles, globals.gridx, globals.gridy);
  646.  
  647.   init_right_bump (width, height);
  648.   init_left_bump  (width, height);
  649.   init_up_bump    (width, height);
  650.   init_down_bump  (width, height);
  651.  
  652.   if (style == BEZIER_1)
  653.     {
  654.       for (i = 0; i < xlines; i++)
  655.     {
  656.           draw_vertical_border (buffer, bufsize, width, height, bytes,
  657.                                 x[i], ytiles,
  658.                 blend_lines, blend_amount, preview_mode);
  659.       if (!preview_mode) 
  660.         gimp_progress_update ((gdouble) i / (gdouble) progress_total);
  661.     }
  662.       for (i = 0; i < ylines; i++)
  663.     {
  664.           draw_horizontal_border (buffer, bufsize, width, bytes, y[i], xtiles,
  665.                   blend_lines, blend_amount, preview_mode);
  666.       if (!preview_mode) 
  667.         gimp_progress_update ((gdouble) (i + xlines) / (gdouble) progress_total);
  668.     }
  669.     }
  670.   else if (style == BEZIER_2)
  671.     {
  672.       for (i = 0; i < xlines; i++)
  673.     {
  674.           draw_bezier_vertical_border (buffer, bufsize, width, height, bytes,
  675.                                        x[i], xtiles, ytiles, blend_lines,
  676.                        blend_amount, steps, preview_mode);
  677.       if (!preview_mode) 
  678.         gimp_progress_update ((gdouble) i / (gdouble) progress_total);
  679.     }
  680.       for (i = 0; i < ylines; i++)
  681.     {
  682.           draw_bezier_horizontal_border (buffer, bufsize, width, height,
  683.                                          bytes, y[i],
  684.                      xtiles, ytiles, blend_lines,
  685.                      blend_amount, steps, preview_mode);
  686.       if (!preview_mode) 
  687.         gimp_progress_update ((gdouble) (i + xlines) / (gdouble) progress_total);
  688.     }
  689.     }
  690.   else
  691.     {
  692.       printf("draw_jigsaw: bad style\n");
  693.       exit(1);
  694.     }
  695.  
  696.   g_free (globals.gridx);
  697.   g_free (globals.gridy);
  698.   
  699.   return;
  700. }
  701.  
  702. static void
  703. draw_vertical_border (guchar  *buffer,
  704.                       gint     bufsize,
  705.               gint     width,
  706.               gint     height,
  707.               gint     bytes,
  708.               gint     x_offset,
  709.               gint     ytiles,
  710.               gint     blend_lines,
  711.               gdouble  blend_amount,
  712.               gboolean preview_mode)
  713. {
  714.   gint i, j;
  715.   gint tile_height = height / ytiles;
  716.   gint tile_height_eighth = tile_height / 8;
  717.   gint curve_start_offset = 3 * tile_height_eighth;
  718.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  719.   gint px[2], py[2];
  720.   gint ly[2], dy[2];
  721.   gint y_offset = 0;
  722.   gdouble delta;
  723.   gdouble sigma = blend_amount / blend_lines;
  724.   gint right;
  725.   bump_t style_index;
  726.  
  727.   for (i = 0; i < ytiles; i++)
  728.     {
  729.       right = rand() & 1;
  730.       if (right)
  731.     {
  732.       style_index = RIGHT;
  733.     }
  734.       else
  735.     {
  736.       style_index = LEFT;
  737.     }
  738.       
  739.       /* first straight line from top downwards */
  740.       px[0] = px[1] = x_offset;
  741.       py[0] = y_offset; py[1] = y_offset + curve_start_offset - 1;
  742.       draw_vertical_line (buffer, bufsize, width, bytes, px, py,
  743.                           preview_mode);
  744.       delta = blend_amount;
  745.       dy[0] = ly[0] = py[0]; dy[1] = ly[1] = py[1];
  746.       if (!right)
  747.     {
  748.       ly[1] += blend_lines + 2;
  749.     }
  750.       for (j = 0; j < blend_lines; j++)
  751.     {
  752.       dy[0]++; dy[1]--; ly[0]++; ly[1]--;
  753.       px[0] = x_offset - j - 1;
  754.           darken_vertical_line (buffer, bufsize, width, bytes, px, dy, delta,
  755.                                 preview_mode);
  756.       px[0] = x_offset + j + 1;
  757.           lighten_vertical_line (buffer, bufsize, width, bytes, px, ly, delta,
  758.                                  preview_mode);
  759.       delta -= sigma;
  760.     }
  761.  
  762.       /* top half of curve */
  763.       if (right)
  764.     {
  765.           draw_right_bump (buffer, bufsize, width, bytes, x_offset,
  766.                y_offset + curve_start_offset,
  767.                globals.steps[RIGHT], preview_mode);
  768.       delta = blend_amount;
  769.       for (j = 0; j < blend_lines; j++)
  770.         {
  771.           /* use to be -j -1 */
  772.               darken_right_bump (buffer, bufsize, width, bytes, x_offset,
  773.                  y_offset + curve_start_offset,
  774.                  globals.steps[RIGHT], delta, j, preview_mode);
  775.           /* use to be +j + 1 */
  776.               lighten_right_bump (buffer, bufsize, width, bytes, x_offset,
  777.                   y_offset + curve_start_offset,
  778.                   globals.steps[RIGHT], delta, j, preview_mode);
  779.           delta -= sigma;
  780.         }
  781.     }
  782.       else
  783.     {
  784.           draw_left_bump (buffer, bufsize, width, bytes, x_offset,
  785.               y_offset + curve_start_offset,
  786.               globals.steps[LEFT], preview_mode);
  787.       delta = blend_amount;
  788.       for (j = 0; j < blend_lines; j++)
  789.         {
  790.           /* use to be -j -1 */
  791.               darken_left_bump (buffer, bufsize, width, bytes, x_offset,
  792.                 y_offset + curve_start_offset,
  793.                 globals.steps[LEFT], delta, j, preview_mode);
  794.           /* use to be -j - 1 */
  795.               lighten_left_bump (buffer, bufsize, width, bytes, x_offset,
  796.                  y_offset + curve_start_offset,
  797.                  globals.steps[LEFT], delta, j, preview_mode);
  798.           delta -= sigma;
  799.         }
  800.     }
  801.       /* bottom straight line of a tile wall */
  802.       px[0] = px[1] = x_offset;
  803.       py[0] = y_offset + curve_end_offset;
  804.       py[1] = globals.gridy[i];
  805.       draw_vertical_line (buffer, bufsize, width, bytes, px, py,
  806.                           preview_mode);
  807.       delta = blend_amount;
  808.       dy[0] = ly[0] = py[0]; dy[1] = ly[1] = py[1];
  809.       if (right)
  810.     {
  811.       dy[0] -= blend_lines + 2;
  812.     }
  813.       for (j = 0; j < blend_lines; j++)
  814.     {
  815.       dy[0]++; dy[1]--; ly[0]++; ly[1]--;
  816.       px[0] = x_offset - j - 1;
  817.           darken_vertical_line (buffer, bufsize, width, bytes, px, dy, delta,
  818.                                 preview_mode);
  819.       px[0] = x_offset + j + 1;
  820.           lighten_vertical_line (buffer, bufsize, width, bytes, px, ly, delta,
  821.                                  preview_mode);
  822.       delta -= sigma;
  823.     }
  824.  
  825.       y_offset = globals.gridy[i];
  826.     }  /* for */
  827.   
  828.   return;
  829. }
  830.  
  831. /* assumes RGB* */
  832. static void
  833. draw_horizontal_border (guchar   *buffer,
  834.                         gint      bufsize,
  835.             gint      width,
  836.             gint      bytes,
  837.             gint      y_offset,
  838.             gint      xtiles,
  839.             gint      blend_lines,
  840.             gdouble   blend_amount,
  841.             gboolean  preview_mode)
  842. {
  843.   gint i, j;
  844.   gint tile_width = width / xtiles;
  845.   gint tile_width_eighth = tile_width / 8;
  846.   gint curve_start_offset = 3 * tile_width_eighth;
  847.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  848.   gint px[2], py[2];
  849.   gint dx[2], lx[2];
  850.   gint x_offset = 0;
  851.   gdouble delta;
  852.   gdouble sigma = blend_amount / blend_lines;
  853.   gint up;
  854.  
  855.   for (i = 0; i < xtiles; i++)
  856.     {
  857.       up = rand() & 1;
  858.       /* first horizontal line across */
  859.       px[0] = x_offset; px[1] = x_offset + curve_start_offset - 1;
  860.       py[0] = py[1] = y_offset;
  861.       draw_horizontal_line (buffer, bufsize, width, bytes, px, py,
  862.                             preview_mode);
  863.       delta = blend_amount;
  864.       dx[0] = lx[0] = px[0]; dx[1] = lx[1] = px[1];
  865.       if (up)
  866.     {
  867.       lx[1] += blend_lines + 2;
  868.     }
  869.       for (j = 0; j < blend_lines; j++)
  870.     {
  871.       dx[0]++; dx[1]--; lx[0]++; lx[1]--;
  872.       py[0] = y_offset - j - 1;
  873.           darken_horizontal_line (buffer, bufsize, width, bytes, dx, py,
  874.                                   delta, preview_mode);
  875.       py[0] = y_offset + j + 1;
  876.           lighten_horizontal_line (buffer, bufsize, width, bytes, lx, py,
  877.                                    delta, preview_mode);
  878.       delta -= sigma;
  879.     }
  880.  
  881.       if (up)
  882.     {
  883.           draw_up_bump (buffer, bufsize, width, bytes, y_offset,
  884.             x_offset + curve_start_offset,
  885.             globals.steps[UP], preview_mode);
  886.       delta = blend_amount;
  887.       for (j = 0; j < blend_lines; j++)
  888.         {
  889.           /* use to be -j -1 */
  890.               darken_up_bump (buffer, bufsize, width, bytes, y_offset,
  891.                   x_offset + curve_start_offset,
  892.                   globals.steps[UP], delta, j, preview_mode);
  893.           /* use to be +j + 1 */
  894.               lighten_up_bump (buffer, bufsize, width, bytes, y_offset,
  895.                    x_offset + curve_start_offset,
  896.                    globals.steps[UP], delta, j, preview_mode);
  897.           delta -= sigma;
  898.         }
  899.     }
  900.       else
  901.     {
  902.           draw_down_bump (buffer, bufsize, width, bytes, y_offset,
  903.               x_offset + curve_start_offset,
  904.               globals.steps[DOWN], preview_mode);
  905.       delta = blend_amount;
  906.       for (j = 0; j < blend_lines; j++)
  907.         {
  908.           /* use to be +j + 1 */
  909.               darken_down_bump (buffer, bufsize, width, bytes, y_offset,
  910.                 x_offset + curve_start_offset,
  911.                 globals.steps[DOWN], delta, j, preview_mode);
  912.           /* use to be -j -1 */
  913.               lighten_down_bump (buffer, bufsize, width, bytes, y_offset,
  914.                  x_offset + curve_start_offset,
  915.                  globals.steps[DOWN], delta, j, preview_mode);
  916.           delta -= sigma;
  917.         }
  918.     }
  919.       /* right horizontal line of tile */
  920.       px[0] = x_offset + curve_end_offset;
  921.       px[1] = globals.gridx[i];
  922.       py[0] = py[1] = y_offset;
  923.       draw_horizontal_line (buffer, bufsize, width, bytes, px, py,
  924.                             preview_mode);
  925.       delta = blend_amount;
  926.       dx[0] = lx[0] = px[0]; dx[1] = lx[1] = px[1];
  927.       if (!up)
  928.     {
  929.       dx[0] -= blend_lines + 2;
  930.     }
  931.       for (j = 0;j < blend_lines; j++)
  932.     {
  933.       dx[0]++; dx[1]--; lx[0]++; lx[1]--;
  934.       py[0] = y_offset - j - 1;
  935.           darken_horizontal_line (buffer, bufsize, width, bytes, dx, py,
  936.                                   delta, preview_mode);
  937.       py[0] = y_offset + j + 1;
  938.           lighten_horizontal_line (buffer, bufsize, width, bytes, lx, py,
  939.                                    delta, preview_mode);
  940.       delta -= sigma;
  941.     }
  942.       x_offset = globals.gridx[i];
  943.     }  /* for */
  944. }
  945.  
  946. /* assumes going top to bottom */
  947. static void
  948. draw_vertical_line (guchar   *buffer,
  949.                     gint      bufsize,
  950.             gint      width,
  951.             gint      bytes,
  952.             gint      px[2],
  953.             gint      py[2],
  954.             gboolean  preview_mode)
  955. {
  956.   gint i;
  957.   gint rowstride;
  958.   gint index;
  959.   gint length;
  960.   
  961.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  962.   index = px[0] * bytes + rowstride * py[0];
  963.   length = py[1] - py[0] + 1;
  964.  
  965.   for (i = 0; i < length; i++)
  966.     {
  967.       DRAW_POINT (buffer, bufsize, index);
  968.       index += rowstride;
  969.     }
  970. }
  971.  
  972. /* assumes going left to right */
  973. static void
  974. draw_horizontal_line (guchar   *buffer,
  975.                       gint      bufsize,
  976.               gint      width,
  977.               gint      bytes,
  978.               gint      px[2],
  979.               gint      py[2],
  980.               gboolean  preview_mode)
  981. {
  982.   gint i;
  983.   gint rowstride;
  984.   gint index;
  985.   gint length;
  986.   
  987.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  988.   index = px[0] * bytes + rowstride * py[0];
  989.   length = px[1] - px[0] + 1;
  990.  
  991.   for (i = 0; i < length; i++)
  992.     {
  993.       DRAW_POINT (buffer, bufsize, index);
  994.       index += bytes;
  995.     }
  996. }
  997.  
  998. static void
  999. draw_right_bump (guchar   *buffer,
  1000.                  gint      bufsize,
  1001.          gint      width,
  1002.          gint      bytes,
  1003.          gint      x_offset,
  1004.          gint      curve_start_offset,
  1005.          gint      steps,
  1006.          gboolean  preview_mode)
  1007. {
  1008.   gint i;
  1009.   gint x, y;
  1010.   gint index;
  1011.   gint rowstride;
  1012.  
  1013.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1014.  
  1015.   for (i = 0; i < steps; i++)
  1016.     {
  1017.       x = *(globals.cachex1[RIGHT] + i) + x_offset;
  1018.       y = *(globals.cachey1[RIGHT] + i) + curve_start_offset;
  1019.       index = y * rowstride + x * bytes;
  1020.       DRAW_POINT (buffer, bufsize, index);
  1021.  
  1022.       x = *(globals.cachex2[RIGHT] + i) + x_offset;
  1023.       y = *(globals.cachey2[RIGHT] + i) + curve_start_offset;
  1024.       index = y * rowstride + x * bytes;
  1025.       DRAW_POINT (buffer, bufsize, index);
  1026.     }
  1027. }
  1028.  
  1029. static void
  1030. draw_left_bump (guchar   *buffer,
  1031.                 gint      bufsize,
  1032.         gint      width,
  1033.         gint      bytes,
  1034.         gint      x_offset,
  1035.         gint      curve_start_offset,
  1036.         gint      steps,
  1037.         gboolean  preview_mode)
  1038. {
  1039.   gint i;
  1040.   gint x, y;
  1041.   gint index;
  1042.   gint rowstride;
  1043.  
  1044.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1045.  
  1046.   for (i = 0; i < steps; i++)
  1047.     {
  1048.       x = *(globals.cachex1[LEFT] + i) + x_offset;
  1049.       y = *(globals.cachey1[LEFT] + i) + curve_start_offset;
  1050.       index = y * rowstride + x * bytes;
  1051.       DRAW_POINT (buffer, bufsize, index);
  1052.  
  1053.       x = *(globals.cachex2[LEFT] + i) + x_offset;
  1054.       y = *(globals.cachey2[LEFT] + i) + curve_start_offset;
  1055.       index = y * rowstride + x * bytes;
  1056.       DRAW_POINT (buffer, bufsize, index);
  1057.     }
  1058. }
  1059.  
  1060. static void
  1061. draw_up_bump (guchar   *buffer,
  1062.               gint      bufsize,
  1063.           gint      width,
  1064.           gint      bytes,
  1065.           gint      y_offset,
  1066.           gint      curve_start_offset,
  1067.           gint      steps,
  1068.           gboolean  preview_mode)
  1069. {
  1070.   gint i;
  1071.   gint x, y;
  1072.   gint index;
  1073.   gint rowstride;
  1074.  
  1075.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1076.  
  1077.   for (i = 0; i < steps; i++)
  1078.     {
  1079.       x = *(globals.cachex1[UP] + i) + curve_start_offset;
  1080.       y = *(globals.cachey1[UP] + i) + y_offset;
  1081.       index = y * rowstride + x * bytes;
  1082.       DRAW_POINT (buffer, bufsize, index);
  1083.  
  1084.       x = *(globals.cachex2[UP] + i) + curve_start_offset;
  1085.       y = *(globals.cachey2[UP] + i) + y_offset;
  1086.       index = y * rowstride + x * bytes;
  1087.       DRAW_POINT (buffer, bufsize, index);
  1088.     }
  1089. }
  1090.  
  1091. static void
  1092. draw_down_bump (guchar   *buffer,
  1093.                 gint      bufsize,
  1094.         gint      width,
  1095.         gint      bytes,
  1096.         gint      y_offset,
  1097.         gint      curve_start_offset,
  1098.         gint      steps,
  1099.         gboolean  preview_mode)
  1100. {
  1101.   gint i;
  1102.   gint x, y;
  1103.   gint index;
  1104.   gint rowstride;
  1105.  
  1106.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1107.  
  1108.   for (i = 0; i < steps; i++)
  1109.     {
  1110.       x = *(globals.cachex1[DOWN] + i) + curve_start_offset;
  1111.       y = *(globals.cachey1[DOWN] + i) + y_offset;
  1112.       index = y * rowstride + x * bytes;
  1113.       DRAW_POINT (buffer, bufsize, index);
  1114.  
  1115.       x = *(globals.cachex2[DOWN] + i) + curve_start_offset;
  1116.       y = *(globals.cachey2[DOWN] + i) + y_offset;
  1117.       index = y * rowstride + x * bytes;
  1118.       DRAW_POINT (buffer, bufsize, index);
  1119.     }
  1120. }
  1121.  
  1122. static void
  1123. malloc_cache (void)
  1124. {
  1125.   gint i, j;
  1126.   gint blend_lines = config.blend_lines;
  1127.   gint length = blend_lines * sizeof(gint *);
  1128.  
  1129.   for (i = 0; i < 4; i++)
  1130.     {
  1131.       gint steps_length = globals.steps[i] * sizeof(gint);
  1132.  
  1133.       globals.cachex1[i] = g_malloc (steps_length);
  1134.       globals.cachex2[i] = g_malloc (steps_length);
  1135.       globals.cachey1[i] = g_malloc (steps_length);
  1136.       globals.cachey2[i] = g_malloc (steps_length);
  1137.       globals.blend_outer_cachex1[i] = g_malloc (length);
  1138.       globals.blend_outer_cachex2[i] = g_malloc (length);
  1139.       globals.blend_outer_cachey1[i] = g_malloc (length);
  1140.       globals.blend_outer_cachey2[i] = g_malloc (length);
  1141.       globals.blend_inner_cachex1[i] = g_malloc (length);
  1142.       globals.blend_inner_cachex2[i] = g_malloc (length);
  1143.       globals.blend_inner_cachey1[i] = g_malloc (length);
  1144.       globals.blend_inner_cachey2[i] = g_malloc (length);
  1145.       for (j = 0; j < blend_lines; j++)
  1146.     {
  1147.       *(globals.blend_outer_cachex1[i] + j) = g_malloc (steps_length);
  1148.       *(globals.blend_outer_cachex2[i] + j) = g_malloc (steps_length);
  1149.       *(globals.blend_outer_cachey1[i] + j) = g_malloc (steps_length);
  1150.       *(globals.blend_outer_cachey2[i] + j) = g_malloc (steps_length);
  1151.       *(globals.blend_inner_cachex1[i] + j) = g_malloc (steps_length);
  1152.       *(globals.blend_inner_cachex2[i] + j) = g_malloc (steps_length);
  1153.       *(globals.blend_inner_cachey1[i] + j) = g_malloc (steps_length);
  1154.       *(globals.blend_inner_cachey2[i] + j) = g_malloc (steps_length);
  1155.     }
  1156.     }
  1157. }
  1158.  
  1159. static void
  1160. free_cache (void)
  1161. {
  1162.   gint i, j;
  1163.   gint blend_lines = config.blend_lines;
  1164.  
  1165.   for (i = 0; i < 4; i ++)
  1166.     {
  1167.       g_free (globals.cachex1[i]);
  1168.       g_free (globals.cachex2[i]);
  1169.       g_free (globals.cachey1[i]);
  1170.       g_free (globals.cachey2[i]);
  1171.       for (j = 0; j < blend_lines; j++)
  1172.     {
  1173.       g_free (*(globals.blend_outer_cachex1[i] + j));
  1174.       g_free (*(globals.blend_outer_cachex2[i] + j));
  1175.       g_free (*(globals.blend_outer_cachey1[i] + j));
  1176.       g_free (*(globals.blend_outer_cachey2[i] + j));
  1177.       g_free (*(globals.blend_inner_cachex1[i] + j));
  1178.       g_free (*(globals.blend_inner_cachex2[i] + j));
  1179.       g_free (*(globals.blend_inner_cachey1[i] + j));
  1180.       g_free (*(globals.blend_inner_cachey2[i] + j));
  1181.     }
  1182.       g_free (globals.blend_outer_cachex1[i]);
  1183.       g_free (globals.blend_outer_cachex2[i]);
  1184.       g_free (globals.blend_outer_cachey1[i]);
  1185.       g_free (globals.blend_outer_cachey2[i]);
  1186.       g_free (globals.blend_inner_cachex1[i]);
  1187.       g_free (globals.blend_inner_cachex2[i]);
  1188.       g_free (globals.blend_inner_cachey1[i]);
  1189.       g_free (globals.blend_inner_cachey2[i]);
  1190.     }
  1191. }
  1192.  
  1193. static void
  1194. init_right_bump (gint width,
  1195.          gint height)
  1196. {
  1197.   gint i;
  1198.   gint xtiles = config.x;
  1199.   gint ytiles = config.y;
  1200.   gint steps = globals.steps[RIGHT];
  1201.   gint px[4], py[4];
  1202.   gint x_offset = 0;
  1203.   gint tile_width =  width / xtiles;
  1204.   gint tile_height = height/ ytiles;
  1205.   gint tile_height_eighth = tile_height / 8;
  1206.   gint curve_start_offset = 0;
  1207.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  1208.   gint blend_lines = config.blend_lines;
  1209.  
  1210.   px[0] = x_offset;
  1211.   px[1] = x_offset + XFACTOR2 * tile_width;
  1212.   px[2] = x_offset + XFACTOR3 * tile_width;
  1213.   px[3] = x_offset + XFACTOR4 * tile_width;
  1214.   py[0] = curve_start_offset;
  1215.   py[1] = curve_start_offset + YFACTOR2 * tile_height;
  1216.   py[2] = curve_start_offset - YFACTOR3 * tile_height;
  1217.   py[3] = curve_start_offset + YFACTOR4 * tile_height;
  1218.   generate_bezier(px, py, steps, globals.cachex1[RIGHT],
  1219.           globals.cachey1[RIGHT]);
  1220.   /* outside right bump */
  1221.   for (i = 0; i < blend_lines; i++)
  1222.     {
  1223.        py[0]--; py[1]--; py[2]--; px[3]++;
  1224.        generate_bezier(px, py, steps,
  1225.                *(globals.blend_outer_cachex1[RIGHT] + i),
  1226.                *(globals.blend_outer_cachey1[RIGHT] + i));
  1227.     }
  1228.   /* inside right bump */
  1229.   py[0] += blend_lines; py[1] += blend_lines; py[2] += blend_lines;
  1230.   px[3] -= blend_lines;
  1231.   for (i = 0; i < blend_lines; i++)
  1232.     {
  1233.       py[0]++; py[1]++; py[2]++; px[3]--;
  1234.       generate_bezier(px, py, steps,
  1235.               *(globals.blend_inner_cachex1[RIGHT] + i),
  1236.               *(globals.blend_inner_cachey1[RIGHT] + i));
  1237.     }
  1238.  
  1239.   /* bottom half of bump */
  1240.   px[0] = x_offset + XFACTOR5 * tile_width;
  1241.   px[1] = x_offset + XFACTOR6 * tile_width;
  1242.   px[2] = x_offset + XFACTOR7 * tile_width;
  1243.   px[3] = x_offset;
  1244.   py[0] = curve_start_offset + YFACTOR5 * tile_height;
  1245.   py[1] = curve_start_offset + YFACTOR6 * tile_height;
  1246.   py[2] = curve_start_offset + YFACTOR7 * tile_height;
  1247.   py[3] = curve_end_offset;
  1248.   generate_bezier(px, py, steps, globals.cachex2[RIGHT],
  1249.           globals.cachey2[RIGHT]);
  1250.   /* outer right bump */
  1251.   for (i = 0; i < blend_lines; i++)
  1252.     {
  1253.       py[1]++; py[2]++; py[3]++; px[0]++;
  1254.       generate_bezier(px, py, steps,
  1255.               *(globals.blend_outer_cachex2[RIGHT] + i),
  1256.               *(globals.blend_outer_cachey2[RIGHT] + i));
  1257.     }
  1258.   /* inner right bump */
  1259.   py[1] -= blend_lines; py[2] -= blend_lines; py[3] -= blend_lines;
  1260.   px[0] -= blend_lines;
  1261.   for (i = 0; i < blend_lines; i++)
  1262.     {
  1263.       py[1]--; py[2]--; py[3]--; px[0]--;
  1264.       generate_bezier(px, py, steps,
  1265.               *(globals.blend_inner_cachex2[RIGHT] + i),
  1266.               *(globals.blend_inner_cachey2[RIGHT] + i));
  1267.     }
  1268.   return;
  1269. }
  1270.  
  1271. static void
  1272. init_left_bump (gint width,
  1273.         gint height)
  1274. {
  1275.   gint i;
  1276.   gint xtiles = config.x;
  1277.   gint ytiles = config.y;
  1278.   gint steps = globals.steps[LEFT];
  1279.   gint px[4], py[4];
  1280.   gint x_offset = 0;
  1281.   gint tile_width = width / xtiles;
  1282.   gint tile_height = height / ytiles;
  1283.   gint tile_height_eighth = tile_height / 8;
  1284.   gint curve_start_offset = 0;
  1285.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  1286.   gint blend_lines = config.blend_lines;
  1287.  
  1288.   px[0] = x_offset;
  1289.   px[1] = x_offset - XFACTOR2 * tile_width;
  1290.   px[2] = x_offset - XFACTOR3 * tile_width;
  1291.   px[3] = x_offset - XFACTOR4 * tile_width;
  1292.   py[0] = curve_start_offset;
  1293.   py[1] = curve_start_offset + YFACTOR2 * tile_height;
  1294.   py[2] = curve_start_offset - YFACTOR3 * tile_height;
  1295.   py[3] = curve_start_offset + YFACTOR4 * tile_height;
  1296.   generate_bezier(px, py, steps, globals.cachex1[LEFT],
  1297.           globals.cachey1[LEFT]);
  1298.   /* outer left bump */
  1299.   for (i = 0; i < blend_lines; i++)
  1300.     {
  1301.       py[0]--; py[1]--; py[2]--; px[3]--;
  1302.       generate_bezier(px, py, steps,
  1303.               *(globals.blend_outer_cachex1[LEFT] + i),
  1304.               *(globals.blend_outer_cachey1[LEFT] + i));
  1305.     }
  1306.   /* inner left bump */
  1307.   py[0] += blend_lines; py[1] += blend_lines; py[2] += blend_lines;
  1308.   px[3] += blend_lines;
  1309.   for (i = 0; i < blend_lines; i++)
  1310.     {
  1311.       py[0]++; py[1]++; py[2]++; px[3]++;
  1312.       generate_bezier(px, py, steps,
  1313.               *(globals.blend_inner_cachex1[LEFT] + i),
  1314.               *(globals.blend_inner_cachey1[LEFT] + i));
  1315.     }
  1316.  
  1317.   /* bottom half of bump */
  1318.   px[0] = x_offset - XFACTOR5 * tile_width;
  1319.   px[1] = x_offset - XFACTOR6 * tile_width;
  1320.   px[2] = x_offset - XFACTOR7 * tile_width;
  1321.   px[3] = x_offset;
  1322.   py[0] = curve_start_offset + YFACTOR5 * tile_height;
  1323.   py[1] = curve_start_offset + YFACTOR6 * tile_height;
  1324.   py[2] = curve_start_offset + YFACTOR7 * tile_height;
  1325.   py[3] = curve_end_offset;
  1326.   generate_bezier(px, py, steps, globals.cachex2[LEFT],
  1327.           globals.cachey2[LEFT]);
  1328.   /* outer left bump */
  1329.   for (i = 0; i < blend_lines; i++)
  1330.     {
  1331.       py[1]++; py[2]++; py[3]++; px[0]--;
  1332.       generate_bezier(px, py, steps,
  1333.               *(globals.blend_outer_cachex2[LEFT] + i),
  1334.               *(globals.blend_outer_cachey2[LEFT] + i));
  1335.     }
  1336.   /* inner left bump */
  1337.   py[1] -= blend_lines; py[2] -= blend_lines; py[3] -= blend_lines;
  1338.   px[0] += blend_lines;
  1339.   for (i = 0; i < blend_lines; i++)
  1340.     {
  1341.       py[1]--; py[2]--; py[3]--; px[0]++;
  1342.       generate_bezier(px, py, steps,
  1343.               *(globals.blend_inner_cachex2[LEFT] + i),
  1344.               *(globals.blend_inner_cachey2[LEFT] + i));
  1345.     }
  1346. }
  1347.  
  1348. static void
  1349. init_up_bump (gint width,
  1350.           gint height)
  1351. {
  1352.   gint i;
  1353.   gint xtiles = config.x;
  1354.   gint ytiles = config.y;
  1355.   gint steps = globals.steps[UP];
  1356.   gint px[4], py[4];
  1357.   gint y_offset = 0;
  1358.   gint tile_width =  width / xtiles;
  1359.   gint tile_height = height/ ytiles;
  1360.   gint tile_width_eighth = tile_width / 8;
  1361.   gint curve_start_offset = 0;
  1362.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  1363.   gint blend_lines = config.blend_lines;
  1364.  
  1365.   px[0] = curve_start_offset;
  1366.   px[1] = curve_start_offset + YFACTOR2 * tile_width;
  1367.   px[2] = curve_start_offset - YFACTOR3 * tile_width;
  1368.   px[3] = curve_start_offset + YFACTOR4 * tile_width;
  1369.   py[0] = y_offset;
  1370.   py[1] = y_offset - XFACTOR2 * tile_height;
  1371.   py[2] = y_offset - XFACTOR3 * tile_height;
  1372.   py[3] = y_offset - XFACTOR4 * tile_height;
  1373.   generate_bezier(px, py, steps, globals.cachex1[UP],
  1374.           globals.cachey1[UP]);
  1375.   /* outer up bump */
  1376.   for (i = 0; i < blend_lines; i++)
  1377.     {
  1378.       px[0]--; px[1]--; px[2]--; py[3]--;
  1379.       generate_bezier(px, py, steps,
  1380.               *(globals.blend_outer_cachex1[UP] + i),
  1381.               *(globals.blend_outer_cachey1[UP] + i));
  1382.     }
  1383.   /* inner up bump */
  1384.   px[0] += blend_lines; px[1] += blend_lines; px[2] += blend_lines;
  1385.   py[3] += blend_lines;
  1386.   for (i = 0; i < blend_lines; i++)
  1387.     {
  1388.       px[0]++; px[1]++; px[2]++; py[3]++;
  1389.       generate_bezier(px, py, steps,
  1390.               *(globals.blend_inner_cachex1[UP] + i),
  1391.               *(globals.blend_inner_cachey1[UP] + i));
  1392.     }
  1393.  
  1394.   /* bottom half of bump */
  1395.   px[0] = curve_start_offset + YFACTOR5 * tile_width;
  1396.   px[1] = curve_start_offset + YFACTOR6 * tile_width;
  1397.   px[2] = curve_start_offset + YFACTOR7 * tile_width;
  1398.   px[3] = curve_end_offset;
  1399.   py[0] = y_offset - XFACTOR5 * tile_height;
  1400.   py[1] = y_offset - XFACTOR6 * tile_height;
  1401.   py[2] = y_offset - XFACTOR7 * tile_height;
  1402.   py[3] = y_offset;
  1403.   generate_bezier(px, py, steps, globals.cachex2[UP],
  1404.           globals.cachey2[UP]);
  1405.   /* outer up bump */
  1406.   for (i = 0; i < blend_lines; i++)
  1407.     {
  1408.       px[1]++; px[2]++; px[3]++; py[0]--;
  1409.       generate_bezier(px, py, steps,
  1410.               *(globals.blend_outer_cachex2[UP] + i),
  1411.               *(globals.blend_outer_cachey2[UP] + i));
  1412.     }
  1413.   /* inner up bump */
  1414.   px[1] -= blend_lines; px[2] -= blend_lines; px[3] -= blend_lines;
  1415.   py[0] += blend_lines;
  1416.   for (i = 0; i < blend_lines; i++)
  1417.     {
  1418.       px[1]--; px[2]--; px[3]--; py[0]++;
  1419.       generate_bezier(px, py, steps,
  1420.               *(globals.blend_inner_cachex2[UP] + i),
  1421.               *(globals.blend_inner_cachey2[UP] + i));
  1422.     }
  1423.   return;
  1424. }
  1425.  
  1426. static void
  1427. init_down_bump (gint width,
  1428.         gint height)
  1429. {
  1430.   gint i;
  1431.   gint xtiles = config.x;
  1432.   gint ytiles = config.y;
  1433.   gint steps = globals.steps[DOWN];
  1434.   gint px[4], py[4];
  1435.   gint y_offset = 0;
  1436.   gint tile_width =  width / xtiles;
  1437.   gint tile_height = height/ ytiles;
  1438.   gint tile_width_eighth = tile_width / 8;
  1439.   gint curve_start_offset = 0;
  1440.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  1441.   gint blend_lines = config.blend_lines;
  1442.  
  1443.   px[0] = curve_start_offset;
  1444.   px[1] = curve_start_offset + YFACTOR2 * tile_width;
  1445.   px[2] = curve_start_offset - YFACTOR3 * tile_width;
  1446.   px[3] = curve_start_offset + YFACTOR4 * tile_width;
  1447.   py[0] = y_offset;
  1448.   py[1] = y_offset + XFACTOR2 * tile_height;
  1449.   py[2] = y_offset + XFACTOR3 * tile_height;
  1450.   py[3] = y_offset + XFACTOR4 * tile_height;
  1451.   generate_bezier(px, py, steps, globals.cachex1[DOWN],
  1452.           globals.cachey1[DOWN]);
  1453.   /* outer down bump */
  1454.   for (i = 0; i < blend_lines; i++)
  1455.     {
  1456.       px[0]--; px[1]--; px[2]--; py[3]++;
  1457.       generate_bezier(px, py, steps,
  1458.               *(globals.blend_outer_cachex1[DOWN] + i),
  1459.               *(globals.blend_outer_cachey1[DOWN] + i));
  1460.     }
  1461.   /* inner down bump */
  1462.   px[0] += blend_lines; px[1] += blend_lines; px[2] += blend_lines;
  1463.   py[3] -= blend_lines;
  1464.   for (i = 0; i < blend_lines; i++)
  1465.     {
  1466.       px[0]++; px[1]++; px[2]++; py[3]--;
  1467.       generate_bezier(px, py, steps,
  1468.               *(globals.blend_inner_cachex1[DOWN] + i),
  1469.               *(globals.blend_inner_cachey1[DOWN] + i));
  1470.     }
  1471.  
  1472.   /* bottom half of bump */
  1473.   px[0] = curve_start_offset + YFACTOR5 * tile_width;
  1474.   px[1] = curve_start_offset + YFACTOR6 * tile_width;
  1475.   px[2] = curve_start_offset + YFACTOR7 * tile_width;
  1476.   px[3] = curve_end_offset;
  1477.   py[0] = y_offset + XFACTOR5 * tile_height;
  1478.   py[1] = y_offset + XFACTOR6 * tile_height;
  1479.   py[2] = y_offset + XFACTOR7 * tile_height;
  1480.   py[3] = y_offset;
  1481.   generate_bezier(px, py, steps, globals.cachex2[DOWN],
  1482.           globals.cachey2[DOWN]);
  1483.   /* outer down bump */
  1484.   for (i = 0; i < blend_lines; i++)
  1485.     {
  1486.       px[1]++; px[2]++; px[3]++; py[0]++;
  1487.       generate_bezier(px, py, steps,
  1488.               *(globals.blend_outer_cachex2[DOWN] + i),
  1489.               *(globals.blend_outer_cachey2[DOWN] + i));
  1490.     }
  1491.   /* inner down bump */
  1492.   px[1] -= blend_lines; px[2] -= blend_lines; px[3] -= blend_lines;
  1493.   py[0] -= blend_lines;
  1494.   for (i = 0; i < blend_lines; i++)
  1495.     {
  1496.       px[1]--; px[2]--; px[3]--; py[0]--;
  1497.       generate_bezier(px, py, steps,
  1498.               *(globals.blend_inner_cachex2[DOWN] + i),
  1499.               *(globals.blend_inner_cachey2[DOWN] + i));
  1500.     }
  1501.   return;
  1502. }
  1503.   
  1504. static void
  1505. generate_grid (gint  width,
  1506.            gint  height,
  1507.            gint  xtiles,
  1508.            gint  ytiles,
  1509.            gint *x,
  1510.            gint *y)
  1511. {
  1512.   gint i;
  1513.   gint xlines = xtiles - 1;
  1514.   gint ylines = ytiles - 1;
  1515.   gint tile_width = width / xtiles;
  1516.   gint tile_height = height / ytiles;
  1517.   gint tile_width_leftover = width % xtiles;
  1518.   gint tile_height_leftover = height % ytiles;
  1519.   gint x_offset = tile_width;
  1520.   gint y_offset = tile_height;
  1521.   gint carry;
  1522.  
  1523.   for (i = 0; i < xlines; i++)
  1524.     {
  1525.       x[i] = x_offset;
  1526.       x_offset += tile_width;
  1527.     }
  1528.   carry = 0;
  1529.   while (tile_width_leftover)
  1530.     {
  1531.       for (i = carry; i < xlines; i++)
  1532.     {
  1533.       x[i] += 1;
  1534.     }
  1535.       tile_width_leftover--;
  1536.       carry++;
  1537.     }
  1538.   x[xlines] = width - 1;    /* padding for draw_horizontal_border */
  1539.   
  1540.   for (i = 0; i < ytiles; i++)
  1541.     {
  1542.       y[i] = y_offset;
  1543.       y_offset += tile_height;
  1544.     }
  1545.   carry = 0;
  1546.   while (tile_height_leftover)
  1547.     {
  1548.       for (i = carry; i < ylines; i++)
  1549.     {
  1550.       y[i] += 1;
  1551.     }
  1552.       tile_height_leftover--;
  1553.       carry++;
  1554.     }
  1555.   y[ylines] = height - 1;   /* padding for draw_vertical_border */
  1556. }
  1557.  
  1558. /* assumes RGB* */
  1559. /* assumes py[1] > py[0] and px[0] = px[1] */
  1560. static void
  1561. darken_vertical_line (guchar   *buffer,
  1562.                       gint      bufsize,
  1563.               gint      width,
  1564.               gint      bytes,
  1565.               gint      px[2],
  1566.               gint      py[2],
  1567.               gdouble   delta,
  1568.               gboolean  preview_mode)
  1569. {
  1570.   gint i;
  1571.   gint rowstride;
  1572.   gint index;
  1573.   gint length;
  1574.   gint temp;
  1575.  
  1576.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1577.   index = px[0] * bytes + py[0] * rowstride;
  1578.   length = py[1] - py[0] + 1;
  1579.  
  1580.   for (i = 0; i < length; i++)
  1581.     {
  1582.       DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1583.       index += rowstride;
  1584.     }
  1585. }
  1586.  
  1587. /* assumes RGB* */
  1588. /* assumes py[1] > py[0] and px[0] = px[1] */
  1589. static void
  1590. lighten_vertical_line (guchar   *buffer,
  1591.                        gint      bufsize,
  1592.                gint      width,
  1593.                gint      bytes,
  1594.                gint      px[2],
  1595.                gint      py[2],
  1596.                gdouble   delta,
  1597.                gboolean  preview_mode)
  1598. {
  1599.   gint i;
  1600.   gint rowstride;
  1601.   gint index;
  1602.   gint length;
  1603.   gint temp;
  1604.  
  1605.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1606.   index = px[0] * bytes + py[0] * rowstride;
  1607.   length = py[1] - py[0] + 1;
  1608.  
  1609.   for (i = 0; i < length; i++)
  1610.     {
  1611.       LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1612.       index += rowstride;
  1613.     }
  1614. }
  1615.  
  1616. /* assumes RGB* */
  1617. /* assumes px[1] > px[0] and py[0] = py[1] */
  1618. static void
  1619. darken_horizontal_line (guchar   *buffer,
  1620.                         gint      bufsize,
  1621.             gint      width,
  1622.             gint      bytes,
  1623.             gint      px[2],
  1624.             gint      py[2],
  1625.             gdouble   delta,
  1626.             gboolean  preview_mode)
  1627. {
  1628.   gint i;
  1629.   gint rowstride;
  1630.   gint index;
  1631.   gint length;
  1632.   gint temp;
  1633.  
  1634.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1635.   index = px[0] * bytes + py[0] * rowstride;
  1636.   length = px[1] - px[0] + 1;
  1637.  
  1638.   for (i = 0; i < length; i++)
  1639.     {
  1640.       DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1641.       index += bytes;
  1642.     }
  1643. }
  1644.  
  1645. /* assumes RGB* */
  1646. /* assumes px[1] > px[0] and py[0] = py[1] */
  1647. static void
  1648. lighten_horizontal_line (guchar   *buffer,
  1649.                          gint      bufsize,
  1650.              gint      width,
  1651.              gint      bytes,
  1652.              gint      px[2],
  1653.              gint      py[2],
  1654.              gdouble   delta,
  1655.              gboolean  preview_mode)
  1656. {
  1657.   gint i;
  1658.   gint rowstride;
  1659.   gint index;
  1660.   gint length;
  1661.   gint temp;
  1662.  
  1663.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1664.   index = px[0] * bytes + py[0] * rowstride;
  1665.   length = px[1] - px[0] + 1;
  1666.  
  1667.   for (i = 0; i < length; i++)
  1668.     {
  1669.       LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1670.       index += bytes;
  1671.     }
  1672. }
  1673.  
  1674. static void
  1675. darken_right_bump (guchar *buffer,
  1676.                    gint    bufsize,
  1677.            gint    width,
  1678.            gint    bytes,
  1679.            gint    x_offset,
  1680.            gint    curve_start_offset,
  1681.            gint    steps,
  1682.            gdouble delta,
  1683.            gint    counter,
  1684.            gboolean  preview_mode)
  1685. {
  1686.   gint i;
  1687.   gint x, y;
  1688.   gint index;
  1689.   gint last_index1 = -1;
  1690.   gint last_index2 = -1;
  1691.   gint rowstride;
  1692.   gint temp;
  1693.   gint j = counter;
  1694.  
  1695.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1696.  
  1697.   for (i = 0; i < steps; i++)
  1698.     {
  1699.       x = x_offset
  1700.     + *(*(globals.blend_inner_cachex1[RIGHT] + j) + i);
  1701.       y = curve_start_offset
  1702.     + *(*(globals.blend_inner_cachey1[RIGHT] + j) + i);
  1703.       index = y * rowstride + x * bytes;
  1704.       if (index != last_index1)
  1705.     {
  1706.       if (i < steps / 1.3)
  1707.         {
  1708.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1709.         }
  1710.       else
  1711.         {
  1712.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1713.         }
  1714.       last_index1 = index;
  1715.     }
  1716.  
  1717.       x = x_offset
  1718.     + *(*(globals.blend_inner_cachex2[RIGHT] + j) + i);
  1719.       y = curve_start_offset
  1720.     + *(*(globals.blend_inner_cachey2[RIGHT] + j) + i);
  1721.       index = y * rowstride + x * bytes;
  1722.       if (index != last_index2)
  1723.     {
  1724.           DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1725.       last_index2 = index;
  1726.     }
  1727.     }
  1728. }
  1729.  
  1730. static void
  1731. lighten_right_bump (guchar   *buffer,
  1732.                     gint      bufsize,
  1733.             gint      width,
  1734.             gint      bytes,
  1735.             gint      x_offset,
  1736.             gint      curve_start_offset,
  1737.             gint      steps,
  1738.             gdouble   delta,
  1739.             gint      counter,
  1740.             gboolean  preview_mode)
  1741. {
  1742.   gint i;
  1743.   gint x, y;
  1744.   gint index;
  1745.   gint last_index1 = -1;
  1746.   gint last_index2 = -1;
  1747.   gint rowstride;
  1748.   gint temp;
  1749.   gint j = counter;
  1750.  
  1751.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1752.  
  1753.   for (i = 0; i < steps; i++)
  1754.     {
  1755.       x = x_offset
  1756.     + *(*(globals.blend_outer_cachex1[RIGHT] + j) + i);
  1757.       y = curve_start_offset
  1758.     + *(*(globals.blend_outer_cachey1[RIGHT] + j) + i);
  1759.       index = y * rowstride + x * bytes;
  1760.       if (index != last_index1)
  1761.     {
  1762.       if (i < steps / 1.3)
  1763.         {
  1764.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1765.         }
  1766.       else
  1767.         {
  1768.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1769.         }
  1770.       last_index1 = index;
  1771.     }
  1772.       
  1773.       x = x_offset
  1774.     + *(*(globals.blend_outer_cachex2[RIGHT] + j) + i);
  1775.       y = curve_start_offset
  1776.     + *(*(globals.blend_outer_cachey2[RIGHT] + j) + i);
  1777.       index = y * rowstride + x * bytes;
  1778.       if (index != last_index2)
  1779.     {
  1780.           LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1781.       last_index2 = index;
  1782.     }
  1783.     }
  1784. }
  1785.  
  1786. static void
  1787. darken_left_bump (guchar   *buffer,
  1788.                   gint      bufsize,
  1789.           gint      width,
  1790.           gint      bytes,
  1791.           gint      x_offset,
  1792.           gint      curve_start_offset,
  1793.           gint      steps,
  1794.           gdouble   delta,
  1795.           gint      counter,
  1796.           gboolean  preview_mode)
  1797. {
  1798.   gint i;
  1799.   gint x, y;
  1800.   gint index;
  1801.   gint last_index1 = -1;
  1802.   gint last_index2 = -1;
  1803.   gint rowstride;
  1804.   gint temp;
  1805.   gint j = counter;
  1806.  
  1807.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1808.  
  1809.   for (i = 0; i < steps; i++)
  1810.     {
  1811.       x = x_offset
  1812.     + *(*(globals.blend_outer_cachex1[LEFT] + j) + i);
  1813.       y = curve_start_offset
  1814.     + *(*(globals.blend_outer_cachey1[LEFT] + j) + i);
  1815.       index = y * rowstride + x * bytes;
  1816.       if (index != last_index1)
  1817.     {
  1818.           DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1819.       last_index1 = index;
  1820.     }
  1821.  
  1822.       x = x_offset
  1823.     + *(*(globals.blend_outer_cachex2[LEFT] + j) + i);
  1824.       y = curve_start_offset
  1825.     + *(*(globals.blend_outer_cachey2[LEFT] + j) + i);
  1826.       index = y * rowstride + x * bytes;
  1827.       if (index != last_index2)
  1828.     {
  1829.       if (i < steps / 4)
  1830.         {
  1831.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1832.         }
  1833.       else
  1834.         {
  1835.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1836.         }
  1837.       last_index2 = index;
  1838.     }
  1839.     }
  1840. }
  1841.  
  1842. static void
  1843. lighten_left_bump (guchar *buffer,
  1844.                    gint    bufsize,
  1845.            gint    width,
  1846.            gint    bytes,
  1847.            gint    x_offset,
  1848.            gint    curve_start_offset,
  1849.            gint    steps,
  1850.            gdouble delta,
  1851.            gint    counter,
  1852.            gboolean  preview_mode)
  1853. {
  1854.   gint i;
  1855.   gint x, y;
  1856.   gint index;
  1857.   gint last_index1 = -1; 
  1858.   gint last_index2 = -1;
  1859.   gint rowstride;
  1860.   gint temp;
  1861.   gint j = counter;
  1862.  
  1863.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1864.  
  1865.   for (i = 0; i < steps; i++)
  1866.     {
  1867.       x = x_offset
  1868.     + *(*(globals.blend_inner_cachex1[LEFT] + j) + i);
  1869.       y = curve_start_offset
  1870.     + *(*(globals.blend_inner_cachey1[LEFT] + j) + i);
  1871.       index = y * rowstride + x * bytes;
  1872.       if (index != last_index1)
  1873.     {
  1874.           LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1875.       last_index1 = index;
  1876.     }
  1877.  
  1878.       x = x_offset
  1879.     + *(*(globals.blend_inner_cachex2[LEFT] + j) + i);
  1880.       y = curve_start_offset
  1881.     + *(*(globals.blend_inner_cachey2[LEFT] + j) + i);
  1882.       index = y * rowstride + x * bytes;
  1883.       if (index != last_index2)
  1884.     {
  1885.       if (i < steps / 4)
  1886.         {
  1887.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1888.         }
  1889.       else
  1890.         {
  1891.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1892.         }
  1893.       last_index2 = index;
  1894.     }
  1895.     }
  1896. }
  1897.  
  1898. static void
  1899. darken_up_bump (guchar   *buffer,
  1900.                 gint      bufsize,
  1901.         gint      width,
  1902.         gint      bytes,
  1903.         gint      y_offset,
  1904.         gint      curve_start_offset,
  1905.         gint      steps,
  1906.         gdouble   delta,
  1907.         gint      counter,
  1908.         gboolean  preview_mode)
  1909. {
  1910.   gint i;
  1911.   gint x, y;
  1912.   gint index;
  1913.   gint last_index1 = -1;
  1914.   gint last_index2 = -1;
  1915.   gint rowstride;
  1916.   gint temp;
  1917.   gint j = counter;
  1918.  
  1919.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1920.  
  1921.   for (i = 0; i < steps; i++)
  1922.     {
  1923.       x = curve_start_offset
  1924.     + *(*(globals.blend_outer_cachex1[UP] + j) + i);
  1925.       y = y_offset
  1926.     + *(*(globals.blend_outer_cachey1[UP] + j) + i);
  1927.       index = y * rowstride + x * bytes;
  1928.       if (index != last_index1)
  1929.     {
  1930.           DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1931.       last_index1 = index;
  1932.     }
  1933.  
  1934.       x = curve_start_offset
  1935.     + *(*(globals.blend_outer_cachex2[UP] + j) + i);
  1936.       y = y_offset
  1937.     + *(*(globals.blend_outer_cachey2[UP] + j) + i);
  1938.       index = y * rowstride + x * bytes;
  1939.       if (index != last_index2)
  1940.     {
  1941.       if (i < steps / 4)
  1942.         {
  1943.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  1944.         }
  1945.       else
  1946.         {
  1947.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1948.         }
  1949.       last_index2 = index;
  1950.     }
  1951.     }
  1952. }
  1953.  
  1954. static void
  1955. lighten_up_bump (guchar   *buffer,
  1956.                  gint      bufsize,
  1957.          gint      width,
  1958.          gint      bytes,
  1959.          gint      y_offset,
  1960.          gint      curve_start_offset,
  1961.          gint      steps,
  1962.          gdouble   delta,
  1963.          gint      counter,
  1964.          gboolean  preview_mode)
  1965. {
  1966.   gint i;
  1967.   gint x, y;
  1968.   gint index;
  1969.   gint last_index1 = -1;
  1970.   gint last_index2 = -1;
  1971.   gint rowstride;
  1972.   gint temp;
  1973.   gint j = counter;
  1974.  
  1975.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1976.  
  1977.   for (i = 0; i < steps; i++)
  1978.     {
  1979.       x = curve_start_offset
  1980.     + *(*(globals.blend_inner_cachex1[UP] + j) + i);
  1981.       y = y_offset
  1982.     + *(*(globals.blend_inner_cachey1[UP] + j) + i);
  1983.       index = y * rowstride + x * bytes;
  1984.       if (index != last_index1)
  1985.     {
  1986.           LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  1987.       last_index1 = index;
  1988.     }
  1989.  
  1990.       x = curve_start_offset
  1991.     + *(*(globals.blend_inner_cachex2[UP] + j) + i);
  1992.       y = y_offset
  1993.     + *(*(globals.blend_inner_cachey2[UP] + j) + i);
  1994.       index = y * rowstride + x * bytes;
  1995.       if (index != last_index2)
  1996.     {
  1997.       if (i < steps / 4)
  1998.         {
  1999.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  2000.         }
  2001.       else
  2002.         {
  2003.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  2004.         }
  2005.       last_index2 = index;
  2006.     }
  2007.     }
  2008. }
  2009.  
  2010. static void
  2011. darken_down_bump (guchar   *buffer,
  2012.                   gint      bufsize,
  2013.           gint      width,
  2014.           gint      bytes,
  2015.           gint      y_offset,
  2016.           gint      curve_start_offset,
  2017.           gint      steps,
  2018.           gdouble   delta,
  2019.           gint      counter,
  2020.           gboolean  preview_mode)
  2021. {
  2022.   gint i;
  2023.   gint x, y;
  2024.   gint index;
  2025.   gint last_index1 = -1;
  2026.   gint last_index2 = -1;
  2027.   gint rowstride;
  2028.   gint temp;
  2029.   gint j = counter;
  2030.  
  2031.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2032.  
  2033.   for (i = 0; i < steps; i++)
  2034.     {
  2035.       x = curve_start_offset
  2036.     + *(*(globals.blend_inner_cachex1[DOWN] + j) + i);
  2037.       y = y_offset
  2038.     + *(*(globals.blend_inner_cachey1[DOWN] + j) + i);
  2039.       index = y * rowstride + x * bytes;
  2040.       if (index != last_index1)
  2041.     {
  2042.       if (i < steps / 1.2)
  2043.         {
  2044.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  2045.         }
  2046.       else
  2047.         {
  2048.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  2049.         }
  2050.       last_index1 = index;
  2051.     }
  2052.  
  2053.       x = curve_start_offset
  2054.     + *(*(globals.blend_inner_cachex2[DOWN] + j) + i);
  2055.       y = y_offset
  2056.     + *(*(globals.blend_inner_cachey2[DOWN] + j) + i);
  2057.       index = y * rowstride + x * bytes;
  2058.       if (index != last_index2)
  2059.     {
  2060.           DARKEN_POINT (buffer, bufsize, index, delta, temp);
  2061.       last_index2 = index;
  2062.     }
  2063.     }
  2064. }
  2065.  
  2066. static void
  2067. lighten_down_bump (guchar   *buffer,
  2068.                    gint      bufsize,
  2069.            gint      width,
  2070.            gint      bytes,
  2071.            gint      y_offset,
  2072.            gint      curve_start_offset,
  2073.            gint      steps,
  2074.            gdouble   delta,
  2075.            gint      counter,
  2076.            gboolean  preview_mode)
  2077. {
  2078.   gint i;
  2079.   gint x, y;
  2080.   gint index;
  2081.   gint last_index1 = -1;
  2082.   gint last_index2 = -1;
  2083.   gint rowstride;
  2084.   gint temp;
  2085.   gint j = counter;
  2086.  
  2087.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2088.  
  2089.   for (i = 0; i < steps; i++)
  2090.     {
  2091.       x = curve_start_offset
  2092.     + *(*(globals.blend_outer_cachex1[DOWN] + j) + i);
  2093.       y = y_offset
  2094.     + *(*(globals.blend_outer_cachey1[DOWN] + j) + i);
  2095.       index = y * rowstride + x * bytes;
  2096.       if (index != last_index1)
  2097.     {
  2098.       if (i < steps / 1.2)
  2099.         {
  2100.               DARKEN_POINT (buffer, bufsize, index, delta, temp);
  2101.         }
  2102.       else
  2103.         {
  2104.               LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  2105.         }
  2106.       last_index1 = index;
  2107.     }
  2108.  
  2109.       x = curve_start_offset
  2110.     + *(*(globals.blend_outer_cachex2[DOWN] + j) + i);
  2111.       y = y_offset
  2112.     + *(*(globals.blend_outer_cachey2[DOWN] + j) + i);
  2113.       index = y * rowstride + x * bytes;
  2114.       if (index != last_index2)
  2115.     {
  2116.           LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  2117.       last_index2 = index;
  2118.     }
  2119.     }
  2120. }
  2121.  
  2122. static void
  2123. draw_bezier_line (guchar   *buffer,
  2124.                   gint      bufsize,
  2125.           gint      width,
  2126.           gint      bytes,
  2127.           gint      steps,
  2128.           gint     *cx,
  2129.           gint     *cy,
  2130.           gboolean  preview_mode)
  2131. {
  2132.   gint i;
  2133.   gint x, y;
  2134.   gint index;
  2135.   gint rowstride;
  2136.  
  2137.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2138.  
  2139.   for (i = 0; i < steps; i++)
  2140.     {
  2141.       x = cx[i];
  2142.       y = cy[i];
  2143.       index = y * rowstride + x * bytes;
  2144.       DRAW_POINT (buffer, bufsize, index);
  2145.     }
  2146. }
  2147.  
  2148. static void
  2149. darken_bezier_line (guchar   *buffer,
  2150.                     gint      bufsize,
  2151.             gint      width,
  2152.             gint      bytes,
  2153.             gint      x_offset,
  2154.             gint      y_offset,
  2155.             gint      steps,
  2156.             gint     *cx,
  2157.             gint     *cy,
  2158.             gdouble   delta,
  2159.             gboolean  preview_mode)
  2160. {
  2161.   gint i;
  2162.   gint x, y;
  2163.   gint index;
  2164.   gint last_index = -1;
  2165.   gint rowstride;
  2166.   gint temp;
  2167.  
  2168.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2169.  
  2170.   for (i = 0; i < steps; i++)
  2171.     {
  2172.       x = cx[i] + x_offset;
  2173.       y = cy[i] + y_offset;
  2174.       index = y * rowstride + x * bytes;
  2175.       if (index != last_index)
  2176.     {
  2177.           DARKEN_POINT (buffer, bufsize, index, delta, temp);
  2178.       last_index = index;
  2179.     }
  2180.     }
  2181. }
  2182.  
  2183. static void
  2184. lighten_bezier_line (guchar   *buffer,
  2185.                      gint      bufsize,
  2186.              gint      width,
  2187.              gint      bytes,
  2188.              gint      x_offset,
  2189.              gint      y_offset,
  2190.              gint      steps,
  2191.              gint     *cx,
  2192.              gint     *cy,
  2193.              gdouble   delta,
  2194.              gboolean  preview_mode)
  2195. {
  2196.   gint i;
  2197.   gint x, y;
  2198.   gint index;
  2199.   gint last_index = -1;
  2200.   gint rowstride;
  2201.   gint temp;
  2202.  
  2203.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2204.  
  2205.   for (i = 0; i < steps; i++)
  2206.     {
  2207.       x = cx[i] + x_offset;
  2208.       y = cy[i] + y_offset;
  2209.       index = y * rowstride + x * bytes;
  2210.       if (index != last_index)
  2211.     {
  2212.           LIGHTEN_POINT (buffer, bufsize, index, delta, temp);
  2213.       last_index = index;
  2214.     }
  2215.     }
  2216. }
  2217.  
  2218. static void
  2219. draw_bezier_vertical_border (guchar   *buffer,
  2220.                              gint      bufsize,
  2221.                  gint      width,
  2222.                  gint      height,
  2223.                  gint      bytes,
  2224.                  gint      x_offset,
  2225.                  gint      xtiles,
  2226.                  gint      ytiles,
  2227.                  gint      blend_lines,
  2228.                  gdouble   blend_amount,
  2229.                  gint      steps,
  2230.                  gboolean  preview_mode)
  2231. {
  2232.   gint i, j;
  2233.   gint tile_width = width / xtiles;
  2234.   gint tile_height = height / ytiles;
  2235.   gint tile_height_eighth = tile_height / 8;
  2236.   gint curve_start_offset = 3 * tile_height_eighth;
  2237.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  2238.   gint px[4], py[4];
  2239.   gint y_offset = 0;
  2240.   gdouble delta;
  2241.   gdouble sigma = blend_amount / blend_lines;
  2242.   gint right;
  2243.   bump_t style_index;
  2244.   gint *cachex, *cachey;
  2245.  
  2246.   cachex = g_new (gint, steps);
  2247.   cachey = g_new (gint, steps);
  2248.   
  2249.   for (i = 0; i < ytiles; i++)
  2250.     {
  2251.       right = rand() & 1;
  2252.       if (right)
  2253.     {
  2254.       style_index = RIGHT;
  2255.     }
  2256.       else
  2257.     {
  2258.       style_index = LEFT;
  2259.     }
  2260.       px[0] = px[3] = x_offset;
  2261.       px[1] = x_offset + WALL_XFACTOR2 * tile_width * FUDGE;
  2262.       px[2] = x_offset + WALL_XFACTOR3 * tile_width * FUDGE;
  2263.       py[0] = y_offset;
  2264.       py[1] = y_offset + WALL_YCONS2 * tile_height;
  2265.       py[2] = y_offset + WALL_YCONS3 * tile_height;
  2266.       py[3] = y_offset + curve_start_offset;
  2267.  
  2268.       if (right)
  2269.     {
  2270.       px[1] = x_offset - WALL_XFACTOR2 * tile_width;
  2271.       px[2] = x_offset - WALL_XFACTOR3 * tile_width;
  2272.     }
  2273.       generate_bezier (px, py, steps, cachex, cachey);
  2274.       draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey,
  2275.                         preview_mode);
  2276.       delta = blend_amount;
  2277.       for (j = 0; j < blend_lines; j++)
  2278.     {
  2279.       px[0] =  -j - 1;
  2280.           darken_bezier_line (buffer, bufsize, width, bytes, px[0], 0,
  2281.                               steps, cachex, cachey, delta, preview_mode);
  2282.       px[0] =  j + 1;
  2283.           lighten_bezier_line (buffer, bufsize, width, bytes, px[0], 0,
  2284.                                steps, cachex, cachey, delta, preview_mode);
  2285.       delta -= sigma;
  2286.     }
  2287.       if (right)
  2288.     {
  2289.           draw_right_bump (buffer, bufsize, width, bytes, x_offset,
  2290.                            y_offset + curve_start_offset,
  2291.                            globals.steps[RIGHT], preview_mode);
  2292.       delta = blend_amount;
  2293.       for (j = 0; j < blend_lines; j++)
  2294.         {
  2295.           /* use to be -j -1 */
  2296.               darken_right_bump (buffer, bufsize, width, bytes, x_offset,
  2297.                                  y_offset + curve_start_offset,
  2298.                                  globals.steps[RIGHT], delta, j,
  2299.                                  preview_mode);
  2300.           /* use to be +j + 1 */
  2301.               lighten_right_bump (buffer, bufsize, width, bytes, x_offset,
  2302.                                   y_offset + curve_start_offset,
  2303.                                   globals.steps[RIGHT], delta, j,
  2304.                                   preview_mode);
  2305.           delta -= sigma;
  2306.         }
  2307.     }
  2308.       else
  2309.     {
  2310.           draw_left_bump (buffer, bufsize, width, bytes, x_offset,
  2311.                           y_offset + curve_start_offset,
  2312.                           globals.steps[LEFT], preview_mode);
  2313.       delta = blend_amount;
  2314.       for (j = 0; j < blend_lines; j++)
  2315.         {
  2316.           /* use to be -j -1 */
  2317.               darken_left_bump (buffer, bufsize, width, bytes, x_offset,
  2318.                                 y_offset + curve_start_offset,
  2319.                                 globals.steps[LEFT], delta, j, preview_mode);
  2320.           /* use to be -j - 1 */
  2321.               lighten_left_bump (buffer, bufsize, width, bytes, x_offset,
  2322.                                  y_offset + curve_start_offset,
  2323.                                  globals.steps[LEFT], delta, j, preview_mode);
  2324.           delta -= sigma;
  2325.         }
  2326.     }
  2327.       px[0] = px[3] = x_offset;
  2328.       px[1] = x_offset + WALL_XFACTOR2 * tile_width * FUDGE;
  2329.       px[2] = x_offset + WALL_XFACTOR3 * tile_width * FUDGE;
  2330.       py[0] = y_offset + curve_end_offset;
  2331.       py[1] = y_offset + curve_end_offset + WALL_YCONS2 * tile_height;
  2332.       py[2] = y_offset + curve_end_offset + WALL_YCONS3 * tile_height;
  2333.       py[3] = globals.gridy[i];
  2334.       if (right)
  2335.     {
  2336.       px[1] = x_offset - WALL_XFACTOR2 * tile_width;
  2337.       px[2] = x_offset - WALL_XFACTOR3 * tile_width;
  2338.     }
  2339.       generate_bezier (px, py, steps, cachex, cachey);
  2340.       draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey,
  2341.                         preview_mode);
  2342.       delta = blend_amount;
  2343.       for (j = 0; j < blend_lines; j++)
  2344.     {
  2345.       px[0] =  -j - 1;
  2346.           darken_bezier_line (buffer, bufsize, width, bytes, px[0], 0,
  2347.                               steps, cachex, cachey, delta, preview_mode);
  2348.       px[0] =  j + 1;
  2349.           lighten_bezier_line (buffer, bufsize, width, bytes, px[0], 0,
  2350.                                steps, cachex, cachey, delta, preview_mode);
  2351.       delta -= sigma;
  2352.     }
  2353.       y_offset = globals.gridy[i];
  2354.     }  /* for */
  2355.   g_free (cachex);
  2356.   g_free (cachey);
  2357. }
  2358.  
  2359. static void
  2360. draw_bezier_horizontal_border (guchar   *buffer,
  2361.                                gint      bufsize,
  2362.                    gint      width,
  2363.                    gint      height,
  2364.                    gint      bytes,
  2365.                    gint      y_offset,
  2366.                    gint      xtiles,
  2367.                    gint      ytiles,
  2368.                    gint      blend_lines,
  2369.                    gdouble   blend_amount,
  2370.                    gint      steps,
  2371.                    gboolean  preview_mode)
  2372. {
  2373.   gint i, j;
  2374.   gint tile_width = width / xtiles;
  2375.   gint tile_height = height / ytiles;
  2376.   gint tile_width_eighth = tile_width / 8;
  2377.   gint curve_start_offset = 3 * tile_width_eighth;
  2378.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  2379.   gint px[4], py[4];
  2380.   gint x_offset = 0;
  2381.   gdouble delta;
  2382.   gdouble sigma = blend_amount / blend_lines;
  2383.   gint up;
  2384.   style_t style_index;
  2385.   gint *cachex, *cachey;
  2386.  
  2387.   cachex = g_new (gint, steps);
  2388.   cachey = g_new (gint, steps);
  2389.  
  2390.   for (i = 0; i < xtiles; i++)
  2391.     {
  2392.       up = rand() & 1;
  2393.       if (up)
  2394.     {
  2395.       style_index = UP;
  2396.     }
  2397.       else
  2398.     {
  2399.       style_index = DOWN;
  2400.     }
  2401.       px[0] = x_offset;
  2402.       px[1] = x_offset + WALL_XCONS2 * tile_width;
  2403.       px[2] = x_offset + WALL_XCONS3 * tile_width;
  2404.       px[3] = x_offset + curve_start_offset;
  2405.       py[0] = py[3] = y_offset;
  2406.       py[1] = y_offset + WALL_YFACTOR2 * tile_height * FUDGE;
  2407.       py[2] = y_offset + WALL_YFACTOR3 * tile_height * FUDGE;
  2408.       if (!up)
  2409.     {
  2410.       py[1] = y_offset - WALL_YFACTOR2 * tile_height;
  2411.       py[2] = y_offset - WALL_YFACTOR3 * tile_height;
  2412.     }
  2413.       generate_bezier (px, py, steps, cachex, cachey);
  2414.       draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey,
  2415.                         preview_mode);
  2416.       delta = blend_amount;
  2417.       for (j = 0; j < blend_lines; j++)
  2418.     {
  2419.       py[0] = -j - 1;
  2420.           darken_bezier_line (buffer, bufsize, width, bytes, 0, py[0],
  2421.                               steps, cachex, cachey, delta, preview_mode);
  2422.       py[0] = j + 1;
  2423.           lighten_bezier_line (buffer, bufsize, width, bytes, 0, py[0],
  2424.                                steps, cachex, cachey, delta, preview_mode);
  2425.       delta -= sigma;
  2426.     }
  2427.       /* bumps */
  2428.       if (up)
  2429.     {
  2430.           draw_up_bump (buffer, bufsize, width, bytes, y_offset,
  2431.                         x_offset + curve_start_offset,
  2432.                         globals.steps[UP], preview_mode);
  2433.       delta = blend_amount;
  2434.       for (j = 0; j < blend_lines; j++)
  2435.         {
  2436.           /* use to be -j -1 */
  2437.               darken_up_bump (buffer, bufsize, width, bytes, y_offset,
  2438.                               x_offset + curve_start_offset,
  2439.                               globals.steps[UP], delta, j, preview_mode);
  2440.           /* use to be +j + 1 */
  2441.               lighten_up_bump (buffer, bufsize, width, bytes, y_offset,
  2442.                                x_offset + curve_start_offset,
  2443.                                globals.steps[UP], delta, j, preview_mode);
  2444.           delta -= sigma;
  2445.         }
  2446.     }
  2447.       else
  2448.     {
  2449.           draw_down_bump (buffer, bufsize, width, bytes, y_offset,
  2450.                           x_offset + curve_start_offset,
  2451.                           globals.steps[DOWN], preview_mode);
  2452.       delta = blend_amount;
  2453.       for (j = 0; j < blend_lines; j++)
  2454.         {
  2455.           /* use to be +j + 1 */
  2456.               darken_down_bump (buffer, bufsize, width, bytes, y_offset,
  2457.                                 x_offset + curve_start_offset,
  2458.                                 globals.steps[DOWN], delta, j, preview_mode);
  2459.           /* use to be -j -1 */
  2460.               lighten_down_bump (buffer, bufsize, width, bytes, y_offset,
  2461.                                  x_offset + curve_start_offset,
  2462.                                  globals.steps[DOWN], delta, j, preview_mode);
  2463.           delta -= sigma;
  2464.         }
  2465.     }
  2466.       /* ending side wall line */
  2467.       px[0] = x_offset + curve_end_offset;
  2468.       px[1] = x_offset + curve_end_offset + WALL_XCONS2 * tile_width;
  2469.       px[2] = x_offset + curve_end_offset + WALL_XCONS3 * tile_width;
  2470.       px[3] = globals.gridx[i];
  2471.       py[0] = py[3] = y_offset;
  2472.       py[1] = y_offset + WALL_YFACTOR2 * tile_height * FUDGE;
  2473.       py[2] = y_offset + WALL_YFACTOR3 * tile_height * FUDGE;
  2474.       if (!up)
  2475.     {
  2476.       py[1] = y_offset - WALL_YFACTOR2 * tile_height;
  2477.       py[2] = y_offset - WALL_YFACTOR3 * tile_height;
  2478.     }
  2479.       generate_bezier (px, py, steps, cachex, cachey);
  2480.       draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey,
  2481.                         preview_mode);
  2482.       delta = blend_amount;
  2483.       for (j = 0; j < blend_lines; j++)
  2484.     {
  2485.       py[0] =  -j - 1;
  2486.           darken_bezier_line (buffer, bufsize, width, bytes, 0, py[0],
  2487.                               steps, cachex, cachey, delta, preview_mode);
  2488.       py[0] =  j + 1;
  2489.           lighten_bezier_line (buffer, bufsize, width, bytes, 0, py[0],
  2490.                                steps, cachex, cachey, delta, preview_mode);
  2491.       delta -= sigma;
  2492.     }
  2493.       x_offset = globals.gridx[i];
  2494.     }  /* for */
  2495.   g_free (cachex);
  2496.   g_free (cachey);
  2497. }
  2498.  
  2499. static void
  2500. check_config (gint width,
  2501.           gint height)
  2502. {
  2503.   gint tile_width, tile_height;
  2504.   gint tile_width_limit, tile_height_limit;
  2505.   
  2506.   if (config.x < 1)
  2507.     {
  2508.       config.x = 1;
  2509.     }
  2510.   if (config.y < 1)
  2511.     {
  2512.       config.y = 1;
  2513.     }
  2514.   if (config.blend_amount < 0)
  2515.     {
  2516.       config.blend_amount = 0;
  2517.     }
  2518.   if (config.blend_amount > 5)
  2519.     {
  2520.       config.blend_amount = 5;
  2521.     }
  2522.   tile_width = width / config.x;
  2523.   tile_height = height / config.y;
  2524.   tile_width_limit = 0.4 * tile_width;
  2525.   tile_height_limit = 0.4 * tile_height;
  2526.   if ((config.blend_lines > tile_width_limit)
  2527.       || (config.blend_lines > tile_height_limit))
  2528.     {
  2529.       config.blend_lines = MIN(tile_width_limit, tile_height_limit);
  2530.     }
  2531. }
  2532.   
  2533. /********************************************************
  2534.   GUI
  2535. ********************************************************/
  2536.  
  2537. static void
  2538. dialog_box (void)
  2539. {
  2540.   GimpDrawable *drawable = globals.drawable;
  2541.   GtkWidget *dlg;
  2542.   GtkWidget *main_hbox;
  2543.   GtkWidget *abox;
  2544.  
  2545.   GtkWidget *main_vbox;
  2546.   GtkWidget *frame;
  2547.   GtkWidget *rbutton1;
  2548.   GtkWidget *rbutton2;
  2549.   GtkWidget *cbutton;
  2550.   GtkWidget *hbox;
  2551.   GtkWidget *table;
  2552.   GtkObject *adj;
  2553.  
  2554.   gimp_ui_init ("jigsaw", TRUE);
  2555.  
  2556.   dlg = gimp_dialog_new (_("Jigsaw"), "jigsaw",
  2557.              gimp_standard_help_func, "filters/jigsaw.html",
  2558.              GTK_WIN_POS_MOUSE,
  2559.              FALSE, TRUE, FALSE,
  2560.  
  2561.              _("OK"), run_callback,
  2562.              NULL, NULL, NULL, TRUE, FALSE,
  2563.              _("Cancel"), gtk_widget_destroy,
  2564.              NULL, 1, NULL, FALSE, TRUE,
  2565.  
  2566.              NULL);
  2567.  
  2568.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  2569.               GTK_SIGNAL_FUNC (gtk_main_quit),
  2570.               NULL);
  2571.  
  2572.   /* init tooltips */
  2573.   gimp_help_init ();
  2574.  
  2575.   if (globals.tooltips == 0)
  2576.     {
  2577.       gimp_help_disable_tooltips ();
  2578.     }
  2579.  
  2580.   main_hbox = gtk_hbox_new (FALSE, 2);
  2581.   gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 6);
  2582.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_hbox, TRUE, TRUE, 0);
  2583.   gtk_widget_show (main_hbox);
  2584.  
  2585.   /* make a nice frame */
  2586.   frame = gtk_frame_new (_("Preview"));
  2587.   gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
  2588.   gtk_box_pack_start (GTK_BOX (main_hbox), frame, FALSE, FALSE, 0);
  2589.   gtk_widget_show (frame);
  2590.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  2591.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  2592.   gtk_container_add (GTK_CONTAINER (frame), abox);
  2593.   gtk_widget_show (abox);
  2594.   frame = gtk_frame_new (NULL);
  2595.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  2596.   gtk_container_add (GTK_CONTAINER (abox), frame);
  2597.   gtk_widget_show (frame);
  2598.   preview = preview_widget (drawable); /* we are here */
  2599.   gtk_container_add (GTK_CONTAINER (frame), preview);
  2600.   jigsaw(1); /* render preview */
  2601.   gtk_widget_show (preview);
  2602.   
  2603.   main_vbox = gtk_vbox_new (FALSE, 4);
  2604.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  2605.   gtk_box_pack_start (GTK_BOX (main_hbox), main_vbox, TRUE, TRUE, 0);
  2606.   gtk_widget_show (main_vbox);
  2607.  
  2608.   frame = gtk_frame_new (_("Number of Tiles"));
  2609.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2610.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  2611.  
  2612.   table = gtk_table_new (2, 3, FALSE);
  2613.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2614.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  2615.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  2616.   gtk_container_add (GTK_CONTAINER (frame), table);
  2617.  
  2618.   /* xtiles */
  2619.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  2620.                   _("Horizontal:"), SCALE_WIDTH, 0,
  2621.                   config.x, MIN_XTILES, MAX_XTILES, 1.0, 4.0, 0,
  2622.                   TRUE, 0, 0,
  2623.                   _("Number of pieces going across"), NULL);
  2624.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2625.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2626.               &config.x);
  2627.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2628.               GTK_SIGNAL_FUNC (jigsaw),
  2629.               NULL);
  2630.  
  2631.   /* ytiles */
  2632.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  2633.                   _("Vertical:"), SCALE_WIDTH, 0,
  2634.                   config.y, MIN_YTILES, MAX_YTILES, 1.0, 4.0, 0,
  2635.                   TRUE, 0, 0,
  2636.                   _("Number of pieces going down"), NULL);
  2637.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2638.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2639.               &config.y);
  2640.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2641.               GTK_SIGNAL_FUNC (jigsaw),
  2642.               NULL);
  2643.  
  2644.   gtk_widget_show (table);
  2645.   gtk_widget_show (frame);
  2646.  
  2647.   frame = gtk_frame_new (_("Bevel Edges"));
  2648.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2649.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  2650.  
  2651.   table = gtk_table_new (2, 3, FALSE);
  2652.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2653.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  2654.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  2655.   gtk_container_add (GTK_CONTAINER (frame), table);
  2656.  
  2657.   /* number of blending lines */
  2658.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  2659.                   _("Bevel Width:"), SCALE_WIDTH, 0,
  2660.                   config.blend_lines,
  2661.                   MIN_BLEND_LINES, MAX_BLEND_LINES, 1.0, 2.0, 0,
  2662.                   TRUE, 0, 0,
  2663.                   _("Degree of slope of each piece's edge"), NULL);
  2664.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2665.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2666.               &config.blend_lines);
  2667.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2668.               GTK_SIGNAL_FUNC (jigsaw),
  2669.               NULL);
  2670.  
  2671.   /* blending amount */
  2672.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  2673.                   _("Highlight:"), SCALE_WIDTH, 0,
  2674.                   config.blend_amount,
  2675.                   MIN_BLEND_AMOUNT, MAX_BLEND_AMOUNT, 0.05, 0.1, 2,
  2676.                   TRUE, 0, 0,
  2677.                   _("The amount of highlighting on the edges "
  2678.                 "of each piece"), NULL);
  2679.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2680.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  2681.               &config.blend_amount);
  2682.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2683.               GTK_SIGNAL_FUNC (jigsaw),
  2684.               NULL);
  2685.  
  2686.   gtk_widget_show (table);
  2687.   gtk_widget_show (frame);
  2688.   
  2689.   /* frame for primitive radio buttons */
  2690.  
  2691.   hbox = gtk_hbox_new (FALSE, 6);
  2692.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  2693.  
  2694.   frame = gimp_radio_group_new2 (TRUE, _("Jigsaw Style"),
  2695.                  jigsaw_radio_button_update,
  2696.                  &config.style, (gpointer) config.style,
  2697.  
  2698.                  _("Square"), (gpointer) BEZIER_1, &rbutton1,
  2699.                  _("Curved"), (gpointer) BEZIER_2, &rbutton2,
  2700.  
  2701.                  NULL);
  2702.  
  2703.   gimp_help_set_help_data (rbutton1, _("Each piece has straight sides"), NULL);
  2704.   gimp_help_set_help_data (rbutton2, _("Each piece has curved sides"), NULL);
  2705.  
  2706.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  2707.   gtk_widget_show (frame);
  2708.  
  2709.   table = gtk_table_new (1, 2, FALSE);
  2710.   gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
  2711.  
  2712.   cbutton = gtk_check_button_new_with_label (_("Disable Tooltips"));
  2713.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cbutton),
  2714.                 globals.tooltips ? FALSE : TRUE);
  2715.   gtk_signal_connect (GTK_OBJECT (cbutton), "toggled",
  2716.               GTK_SIGNAL_FUNC (check_button_callback),
  2717.               NULL);
  2718.   gtk_table_attach (GTK_TABLE (table), cbutton, 0, 1, 1, 2, 0, 0, 0, 20);
  2719.   gtk_widget_show (cbutton);
  2720.   gimp_help_set_help_data (cbutton, _("Toggle Tooltips on/off"), NULL);
  2721.  
  2722.   gtk_widget_show (table);
  2723.   gtk_widget_show (hbox);
  2724.   gtk_widget_show (dlg);
  2725.  
  2726.   gtk_main ();
  2727.   gimp_help_free ();
  2728.   gdk_flush ();
  2729.  
  2730.   return;
  2731. }
  2732.  
  2733. /***************************************************
  2734.   callbacks
  2735.  ***************************************************/
  2736.  
  2737. static void
  2738. run_callback (GtkWidget *widget,
  2739.           gpointer   data)
  2740. {
  2741.   globals.dialog_result = 1;
  2742.  
  2743.   gtk_widget_destroy (GTK_WIDGET (data));
  2744. }
  2745.  
  2746. static void
  2747. check_button_callback (GtkWidget *widget,
  2748.                gpointer   data)
  2749. {
  2750.   if (GTK_TOGGLE_BUTTON (widget)->active)
  2751.     {
  2752.       gimp_help_disable_tooltips ();
  2753.       globals.tooltips = 0;
  2754.     }
  2755.   else
  2756.     {
  2757.       gimp_help_enable_tooltips ();
  2758.       globals.tooltips = 1;
  2759.     }
  2760. }
  2761.  
  2762. static void
  2763. jigsaw_radio_button_update (GtkWidget *widget, 
  2764.                 gpointer data)
  2765. {
  2766.   gimp_radio_button_update (widget, data);
  2767.   if (GTK_TOGGLE_BUTTON (widget)->active)
  2768.     jigsaw (TRUE);
  2769. }
  2770.  
  2771.  
  2772. /* preview library */
  2773.  
  2774. static GtkWidget *
  2775. preview_widget (GimpDrawable *drawable)
  2776. {
  2777.   gint       size;
  2778.   GtkWidget *preview;
  2779.  
  2780.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  2781.   fill_preview_with_thumb (preview, drawable->id);
  2782.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  2783.   preview_bits = g_malloc (size);
  2784.   memcpy (preview_bits, GTK_PREVIEW (preview)->buffer, size);
  2785.  
  2786.   return preview;
  2787. }
  2788.  
  2789. static void
  2790. fill_preview_with_thumb (GtkWidget *widget, 
  2791.              gint32     drawable_ID)
  2792. {
  2793.   guchar  *drawable_data;
  2794.   gint     bpp;
  2795.   gint     x,y;
  2796.   gint     width  = PREVIEW_SIZE;
  2797.   gint     height = PREVIEW_SIZE;
  2798.   guchar  *src;
  2799.   gdouble  r, g, b, a;
  2800.   gdouble  c0, c1;
  2801.   guchar  *p0, *p1;
  2802.   guchar  *even, *odd;
  2803.  
  2804.   bpp = 0; /* Only returned */
  2805.   
  2806.   drawable_data = 
  2807.     gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
  2808.  
  2809.   if (width < 1 || height < 1)
  2810.     return;
  2811.  
  2812.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  2813.  
  2814.   even = g_malloc (width * 3);
  2815.   odd  = g_malloc (width * 3);
  2816.   src = drawable_data;
  2817.  
  2818.   for (y = 0; y < height; y++)
  2819.     {
  2820.       p0 = even;
  2821.       p1 = odd;
  2822.       
  2823.       for (x = 0; x < width; x++) 
  2824.     {
  2825.       if (bpp == 4)
  2826.         {
  2827.           r = ((gdouble)src[x*4+0]) / 255.0;
  2828.           g = ((gdouble)src[x*4+1]) / 255.0;
  2829.           b = ((gdouble)src[x*4+2]) / 255.0;
  2830.           a = ((gdouble)src[x*4+3]) / 255.0;
  2831.         }
  2832.       else if (bpp == 3)
  2833.         {
  2834.           r = ((gdouble)src[x*3+0]) / 255.0;
  2835.           g = ((gdouble)src[x*3+1]) / 255.0;
  2836.           b = ((gdouble)src[x*3+2]) / 255.0;
  2837.           a = 1.0;
  2838.         }
  2839.       else
  2840.         {
  2841.           r = ((gdouble)src[x*bpp+0]) / 255.0;
  2842.           g = b = r;
  2843.           if (bpp == 2)
  2844.         a = ((gdouble)src[x*bpp+1]) / 255.0;
  2845.           else
  2846.         a = 1.0;
  2847.         }
  2848.       
  2849.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  2850.         {
  2851.           c0 = GIMP_CHECK_LIGHT;
  2852.           c1 = GIMP_CHECK_DARK;
  2853.         } 
  2854.       else 
  2855.         {
  2856.           c0 = GIMP_CHECK_DARK;
  2857.           c1 = GIMP_CHECK_LIGHT;
  2858.         }
  2859.       
  2860.     *p0++ = (c0 + (r - c0) * a) * 255.0;
  2861.     *p0++ = (c0 + (g - c0) * a) * 255.0;
  2862.     *p0++ = (c0 + (b - c0) * a) * 255.0;
  2863.     
  2864.     *p1++ = (c1 + (r - c1) * a) * 255.0;
  2865.     *p1++ = (c1 + (g - c1) * a) * 255.0;
  2866.     *p1++ = (c1 + (b - c1) * a) * 255.0;
  2867.     
  2868.       } /* for */
  2869.       
  2870.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  2871.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)odd,  0, y, width);
  2872.       else
  2873.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)even, 0, y, width);
  2874.  
  2875.       src += width * bpp;
  2876.     }
  2877.  
  2878.   g_free (even);
  2879.   g_free (odd);
  2880.   g_free (drawable_data);
  2881. }
  2882.